每次当我们对界面扩大或缩小时,因为改变了界面的大小,界面就会刷新并且绘制在界面上的图案并不属于界面中的元素,当界面刷新时图案就会消失。为了解决这个问题,我们需要创建一个新的类继承原来的界面,并且重写刷新方式,让刷新后的界面也会显示出图案。
创建新的类来继承窗体对象:
public class NewJFrame extends JFrame {}
在创建窗体对象时引用NewJFrame,创建窗体对象:
//引用完成重写刷新方式的窗体对象
NewJFrame pad=new NewJFrame();
pad.setTitle("画图板");
pad.setSize(730,600);
pad.setLocation(280,50);
pad.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout layout=new FlowLayout();
pad.setLayout(layout);
//创建鼠标监听对象
DrawListener d1=new DrawListener();
//添加选择图形的按钮
String[] shapeNames={"直线","实心矩形","矩形","实心三角形","三角形","长方体","圆形","实心圆形"};
for(int i=0;i< shapeNames.length;i++){
JButton btn=new JButton(shapeNames[i]);
pad.add(btn);
btn.addActionListener(d1);
}
//选择画图的颜色
Color[] colors={Color.black,Color.white,Color.gray,Color.lightGray,Color.darkGray,
Color.red,Color.blue,Color.yellow,Color.green,Color.orange,Color.pink,Color.magenta
};
for(int i=0;i< colors.length;i++){
JButton btn=new JButton(" ");
btn.setBackground(colors[i]);
pad.add(btn);
btn.addActionListener(d1);
}
//进行可视化
pad.setVisible(true);
//添加监听对象(鼠标)
pad.addMouseListener(d1);
//获取画笔
Graphics g= pad.getGraphics();
//使界面中的图形渲染器和鼠标监听器中的图形渲染器表示为同一个
d1.g1= g;
//由于要使用d1中的内容,把监听器传入pad对象中
pad.d1=d1;
然后就是编写监听器用来实现画图和调色:
public class DrawListener implements MouseListener , ActionListener {
//添加画笔对象
Graphics g1;
//起始和终末的坐标
int x1,y1,x2,y2;
//进行初始化,防止报错
String shape="直线";
Color color=Color.black;
//创建数组用来存储图案
MyShape[] shapeList=new MyShape[10];
int shapeLength=10;
int shapeCount=0;
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
//获取按钮上的文本
String word=e.getActionCommand();
//进行判断
if(word.equals(" ")){//获取点击按钮的背景颜色,并将其作为画笔改变像素点后的颜色
//创建一个按钮对象指向界面中的按钮
JButton btn=(JButton) e.getSource();
//获取按钮背景色
color=btn.getBackground();
//改变画笔的颜色
g1.setColor(color);
}
else{
shape=word;
}
}
@Override
public void mouseClicked(MouseEvent e){
System.out.println("点击");
}
@Override
public void mousePressed(MouseEvent e){
System.out.println("按下");
//获取按下鼠标时的坐标
x1=e.getX();
y1=e.getY();
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("松开");
//获取松开鼠标时的坐标
x2 = e.getX();
y2 = e.getY();
if(shape.equals(" ")){
return;
}
else{
//将数据输入进画图的类中,并将其存入数组中
MyShape ms=new MyShape();
ms.shapeName=shape;
ms.color=color;
ms.x1=x1;
ms.y1=y1;
ms.x2=x2;
ms.y2=y2;
shapeList[shapeCount++]=ms;
//进行扩容
if(shapeCount==shapeLength){
int newSize=shapeCount+(shapeCount>>1);
MyShape[] newArray=new MyShape[newSize];
for(int i=0;i<shapeLength;i++){
newArray[i]=shapeList[i];
}
shapeList=newArray;
shapeLength=newSize;
}
//进行绘图
ms.drawShape(g1);
}
}
@Override
public void mouseEntered(MouseEvent e){
System.out.println("进入");
}
@Override
public void mouseExited(MouseEvent e){
System.out.println("离开");
}
}
这里要将画出的图案存入数组中,以便刷新时重新在窗体上显示出图案。
因为监听器功能太多,我们就在另一个类中编写绘图的方法,并且在监听器中使用:
public class MyShape {
int x1,y1,x2,y2;
String shapeName;
Color color;
public void drawShape(Graphics g){//实现绘图的方法
g.setColor(color);
//线条
if (shapeName.equals("直线")) {
g.drawLine(x1, y1, x2, y2);
}
//矩形
if (shapeName.equals("矩形")) {
g.drawLine(x1, y1, x2, y1);
g.drawLine(x1, y1, x1, y2);
g.drawLine(x2, y1, x2, y2);
g.drawLine(x1, y2, x2, y2);
}
if (shapeName.equals("实心矩形")) {
g.drawLine(x1, y1, x2, y1);
g.drawLine(x1, y1, x1, y2);
g.drawLine(x2, y1, x2, y2);
g.drawLine(x1, y2, x2, y2);
for (int i = x1; i <= x2; i++) {
g.drawLine(i, y1, i, y2);
}
for (int i = x2; i <= x1; i++) {
g.drawLine(i, y1, i, y2);
}
}
//三角形
if (shapeName.equals("三角形")) {
int i = (x1 + x2) / 2;
g.drawLine(i, y1, x1, y2);
g.drawLine(i, y1, x2, y2);
g.drawLine(x1, y2, x2, y2);
}
if (shapeName.equals("实心三角形")) {
int i = (x1 + x2) / 2;
g.drawLine(i, y1, x1, y2);
g.drawLine(i, y1, x2, y2);
g.drawLine(x1, y2, x2, y2);
for (int j = i; j <= x2; j++) {
int p = x1 + x2 - j;
int y = (j - i) * (y1 - y2) / (i - x2) + y1;
g.drawLine(j, y, j, y2);
g.drawLine(p, y, p, y2);
}
for (int j = i; j >= x2; j--) {
int p = x1 + x2 - j;
int y = (j - i) * (y1 - y2) / (i - x2) + y1;
g.drawLine(j, y2, j, y);
g.drawLine(p, y2, p, y);
}
}
//长方体
if (shapeName.equals("长方体")) {
g.drawLine(x1, y1, x2, y1);
g.drawLine(x1, y1, x1, y2);
g.drawLine(x2, y1, x2, y2);
g.drawLine(x1, y2, x2, y2);
int x = (Math.abs(x1 - x2)) / 4;
int y = (Math.abs(y1 - y2)) / 4;
int x3 = Math.max(x1, x2);
int x4 = Math.min(x1, x2);
int y3 = Math.max(y1, y2);
int y4 = Math.min(y1, y2);
g.drawLine(x4 + x, y4 - y, x4, y4);
g.drawLine(x3 + x, y4 - y, x3, y4);
g.drawLine(x3 + x, y3 - y, x3, y3);
g.drawLine(x4 + x, y4 - y, x3 + x, y4 - y);
g.drawLine(x3 + x, y4 - y, x3 + x, y3 - y);
}
//圆形
if (shapeName.equals("圆形")){
//因为坐标没有小数,这里要强制类型转换
int r=(int)Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))/2;
int x=(x1+x2)/2,y=(y1+y2)/2;
int x3=x-r;
int y3=y-r;
int x4=x+r;
int y4=y+r;
for(int i=x3;i<=x4;i++){
for(int j=y3;j<=y4;j++) {
int r1 = (int) Math.sqrt((i - x) * (i - x) + (j - y) * (j - y));
if (r1 > r - 1 && r1 < r + 1) {
g.drawLine(i, j, i, j);
}
}
}
}
//实心圆形
if (shapeName.equals("实心圆形")){
int r=(int)Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))/2;
int x=(x1+x2)/2,y=(y1+y2)/2;
int x3=x-r;
int y3=y-r;
int x4=x+r;
int y4=y+r;
for(int i=x3;i<=x4;i++){
for(int j=y3;j<=y4;j++) {
int r1 = (int) Math.sqrt((i - x) * (i - x) + (j - y) * (j - y));
if (r1 <= r) {
g.drawLine(i, j, i, j);
}
}
}
}
}
}
最后就是来改变窗体的刷新方式:
public class NewJFrame extends JFrame {
DrawListener d1;
public void paint(Graphics g){
super.paint(g);//刷新窗体本身原本的代码
for(int i=0;i<d1.shapeLength;i++){
MyShape myShape=d1.shapeList[i];
if(myShape==null){//判断元素是否为空
return;
}
//将原来图案绘制在刷新后的窗体中
myShape.drawShape(g);
}
}
}
这里添加的代码就相当于对原本的刷新方式进行了重写。
最后结果如下: