UI界面重绘系列(上):类的继承和方法重写
UI界面重绘系列分为上下两部分。本篇将探讨Java UI界面被改变时,图形的保存和重绘功能的具体实现,以及在此过程中,类的继承和方法重写的原理。内容分为两大块:界面重绘功能的实现与分析整理(干货)。
一、界面重绘功能的实现
1、实现画板功能
我们想要创建一个窗体,窗体内包含两个按钮,分别点击对应的按钮便可实现绘制不同图形的功能。这里我们来完成直线与矩形框的绘制。
1)界面显示类
我们需要创建一个顶级容器类,并创建显示的方法。在容器中添加按钮与监听器对象,具体代码如下:
public class DrawUI {
//显示界面的方法
public void showUI() {
//创建窗体对象
JFrame drawFrame = new JFrame();
//设置窗体的属性
drawFrame.setSize(1000,600);
drawFrame.setLocationRelativeTo(null);
drawFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
drawFrame.setLayout(new FlowLayout());
//创建按钮对象并添加到窗体
JButton btn = new JButton("直线");
JButton rectBtn = new JButton("矩形");
drawFrame.add(btn);
drawFrame.add(rectBtn);
//创建监听器对象
DrawListener drawL = new DrawListener();
//给窗体添加监听器
drawFrame.addMouseListener(drawL);
//给按钮添加监听器
btn.addActionListener(drawL);
rectBtn.addActionListener(drawL);
//设置窗体可见
drawFrame.setVisible(true);
//获取窗体的Graphics对象
Graphics g = drawFrame.getGraphics();
//给监听器的画布对象赋值
drawL.g = g;
}
public static void main(String[] arg) {
//创建界面对象并引用方法
DrawUI ui = new DrawUI();
ui.showUI();
}
}
2)监听器事件
我们继续创建监听器DrawListener类并继承MouseListener和ActionListener,用来监听我们点击按钮的动作,和鼠标点击界面的事件。
public class DrawListener implements MouseListener,ActionListener{
Graphics g;
int x1,x2,y1,y2;
String ShapeStr;
public void actionPerformed(ActionEvent e) {
//获取按钮上的文字
ShapeStr=e.getActionCommand();
}
public void mousePressed(MouseEvent e) {
//获取鼠标点下时的坐标
x1=e.getX();
y1=e.getY();
}
public void mouseReleased(MouseEvent e) {
//获取鼠标松开时的坐标
x2=e.getX();
y2=e.getY();
//判断文字类型,绘制对应图形
if("直线".equals(ShapeStr)) g.drawLine(x1, y1, x2, y2);
else if("矩形".equals(ShapeStr)) g.drawRect(x1, y1, x2-x1, y2-y1);
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
3)功能呈现
现在功能已经实现,如果此时改变窗体的尺寸,或者缩小窗体再打开时,我们会发现,之前画的图形都消失了。
2、图形消失的原因
继续分析,变动窗体时发生了什么?
窗体被改变,图形消失,但按钮仍被保留。但我们知道按钮显示在界面上也是被画出来的,即创建窗体对象时,一定继承了JFrame类中不断画按钮的方法。此方法就是paint(Graphics g),现在我们对它重写,来满足不断重绘界面上图形的功能。
3、重绘功能分析
1)实现步骤
①、方法重写:首先要去完成类的继承,继承关键字:extends
②、创建图形重绘的类,并实现方法
③、在监听器中创建图形数组Shape[ ]用来保存每次画的图形,再传入界面类实现重绘。
2)编写代码
继承JFrame并重写paint(Graphics g)
public class DFrame extends JFrame{
Shape[] data;
public void paint(Graphics g){
//引用父类的绘制方法
super.paint(g);
//重写绘制方法
for(int i=0;i<data.length;i++){
Shape s=data[i];
s.draw(g);
}
}
}
Shape类中创建重绘方法draw(Graphics g)
public class Shape {
int x1,y1,x2,y2;
Color color;
String shape;
public void draw(Graphics g){
g.getColor();
if("直线".equals(shape)) g.drawLine(x1, y1, x2, y2);
else if("矩形".equals(shape)) g.drawRect(x1, y1, x2-x1, y2-y1);
}
}
DrawListener中添加属性:图形数组Shape[ ]
//创建图形数组
Shape[] data=new Shape[10];
//计数count初始化为0
int count=0;
mouseReleased方法中添加如下代码,保存每次所绘制的图形
Shape s=new Shape();
s.color=Color.BLACK;
s.shape=ShapeStr;
s.x1=x1;
s.y1=y1;
s.x2=x2;
s.y2=y2;
//将图形对象s存入数组
data[count++]=s;
并将JFrame对象改为我们的DFrame,再将监听器的图形数组赋给窗体
DFrame drawFrame = new DFrame();
drawFrame.data=drawL.data;
此时我们便完成了图形重绘的功能,再次改变窗体时,我们的图形仍然被保留了下来。
二、分析整理
其实整个图形重绘就是一个继承并重写方法的过程,其中
1、保存实现
保存绘制的图形对象有3个属性:坐标、颜色、类型
保存图形的时间:绘制一个图形,就保存一个
2、关键字
super:代表父类对象
this:代表当前类自己对象
extends:使用格式:public class 子类名 extends 父类名{ }
3、重写要求
父类的方法不能满足子类的需要,则子类可以重写父类的方法。
1、必须要有继承
2、子类中的方法声明,除了访问权限可以扩大,其他(方法名,返回值类型,参数)必须完全保持一致。
例如:paint方法重写时,方法名仍为paint,无返回值,参数仍为Graphics g。
4、初始化的顺序
创建对象必须加载对应的类,Java是按需加载,且只会被加载一次。当程序执行时,需要生成某个类的对象,Java执行引擎会先检查是否加载了这个类,如果没有加载,则先执行类的加载再生成对象,如果已经加载,则直接生成对象。
例如:DrawListener类中已加载Shape类,DFrame类中可直接生成对象
在类的内部,没有初始化的变量都会被默认初始化:基本数据类型的变量初始化为0(boolean变量默认为false),引用类型的变量为null。
5、访问权限
用于控制被修饰的内容能在哪些地方使用:
当前类 | 同一包下 | 同工程文件中不同包下的子类 | 其他 | |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
(缺省) | √ | √ | ||
private | √ |
6、继承
父类和子类是一对多的关系。
在java中使用extends关键字来表示继承关系。当创建一个类时,总是在继承,如果没有明确指出要继承的类,就总是隐式地从根类Object进行继承。
子类会自动继承父类的方法和变量,在子类中可以调用父类的方法和变量。但是限于访问权限,部分属性和方法不能直接使用。当子类中定义与父类相同名称的成员变量时,父类中相同名称的成员变量会被隐藏;同理,成员方法重名时,父类中相同名称的成员方法会被覆盖。隐藏针对成员变量和静态方法,覆盖针对一般方法,它们均可用 super.成员变量名/方法名 进行引用。