前一篇实现了画图,但是拉动界面以后虽然界面窗口还在但是图形消失了,这是为什么呢?又要如何解决这个问题呢?所以今天要说的就是怎么实现图形的“保存”——实际上是重绘。
1.计算机绘图原理
计算机的绘图原理对在界面上的每个像素点用颜色填充实现的。定位方式是:窗口的左上角为坐标原点,向👉右为x正方向,向👇下为y轴正方向。绘图的时候,计算机便根据指令去一一填充绘制。
但是,当界面窗口被拉伸或者压缩之后,界面窗口上的某些像素点消失或者多余。此时,JFrame中的paint会对窗口进行自动绘制
,但是paint无法对所绘制的图形进行重绘,因此图形没有重新展示。
那对所绘的图形也进行重绘呢?此处需要对paint进行改写。
2.重绘
此次重绘的实现方式是——改写paint。
改写方式如下:
public class drawframe extends JFrame{
shapesave[] arr;
public void paint(Graphics g) {
//调用父类的paint方法
super.paint(g);
for(int i=0; i<arr.length; i++) {
//取出对象
shapesave s =arr[i];
//如果对象不为空
if(s != null) {
s.show(g);
}
}
}
}
首先,paint继承了父类对窗口的绘制,如语句:
super.paint(g);
其次,对shapesave中保存的每一个非空arr[i],都可以执行s.show(g)的方法,如语句:
for(int i=0; i<arr.length; i++) {
//取出对象
shapesave s =arr[i];
//如果对象不为空
if(s != null) {
s.show(g);
}
}
由此也可知,生成界面窗口对象的类由JFrame变成了drawframe。故而实现窗口的语句由代码1变成了代码2
- 代码1
//创建窗体
JFrame Drawframe = new JFrame();
- 代码2
//创建窗体
drawframe Drawframe = new drawframe();
2.图形的保存
2.1监听器中对数据的保存
由上可知,shapesave需要实现的功能有:
- 保存鼠标点击以及释放时候的起点、终点位置
- 保存图形类别
- 根据相应的图形类别、鼠标点击以及释放时候的起点、终点位置,重新绘制图形。
对于鼠标点击以及释放时候的起点、终点位置,图形类别可以利用一个数组实现,实现语句如下:
//对于每一个创建的新图形
shapesave s = new shapesave();
//设置图形的数据
s.saveData(startx, starty, endx, endy, Color.red, type);
//存储在数组重
arr[count] = s;
//个数增加
count++;
以上代码放入drawlistener
中,以便于一边监听一边保存。
2.2 重新绘制的方法实现
相应的,对shapesave类的属性、方法进行设计,如下:
public class shapesave {
public int startx, starty,endx, endy;
public Color color;
public String typeStr;
//存储图形参数
public void saveData(int startx,int starty,int endx,int endy,Color color,String typeStr){
this.startx = startx;
this.starty = starty;
this.endx = endx;
this.endy = endy;
this.typeStr = typeStr;
}
//重绘图形
public void show(Graphics g){
//画直线
if("lines".equals(typeStr)){
g.drawLine(startx, starty, endx, endy);
}
//画矩形
if("rectangle".equals(typeStr)){
g.drawRect(startx, starty, 40, 30);
}
//画圆形
if("circle".equals(typeStr)){
Color forec = new Color(0, 0, 0);
g.setColor(forec);
g.fillOval(startx, starty, 40, 40);
}
//画三角形
if("triangle".equals(typeStr)){
g.drawLine(startx, starty, startx+50, starty+50);
g.drawLine(startx+50, starty+50,endx, endy );
g.drawLine(endx, endy,startx, starty);
}
//Gradient
if("Gradient".equals(typeStr)){
for(int i = 0; i < 205; i++){
Color c = new Color(100, 150, i) ;
g.setColor(c);
g.fillOval(startx, starty, 205-i, i);
}
}
//画图案
if("pattern".equals(typeStr)){
for(int i = 0; i < 205; i++){
Color c = new Color(50, i, 220) ;
g.setColor(c);
g.draw3DRect(startx, starty, 250-i, 50, true);
}
}
}
}
3.UI中的数据信息传递
我们注意到,paint的改写过程中,有用到shapesave的新建对象s。并且对s赋值为 shapesave s = arr[i]
。drawframe
中对arr[]
的属性定义如下:
shapesave[] arr;
即,arr[]是一个新建的、空的、shapesave s类型的数组。
为了完成对窗口中数据的传递,需要在drawui中给窗体的图形赋值:
//设置布局
Drawframe.setLayout(new FlowLayout());
//添加鼠标监听器、动作监听器(创建监听器对象):
drawlistener drawl = new drawlistener();
//添加监听器到界面上;
Drawframe.addMouseListener(drawl);
//给窗体的图形赋值
Drawframe.arr = drawl.arr;
这样,shapesave通过监听器中存储的数据由drawui传递给了paint,实现了
整个窗口以及图形的重绘。
欢迎小伙伴们的热情点赞和批评指正!