java应用——高仿XP画板(三:加上重绘功能)

XP画板到今天可以说已经基本实现完毕,出了菜单栏部分的功能。不过我写的代码在实现部分依然有一点缺陷,我会继续更新这篇博客,来完善功能。
首先,从一个大体上来叙述整个代码的实现。
(一)一个Test_main函数为主函数,只有一个功能就是作为整个代码的入口来启动函数,而主函数打开的门是XPDraw类的initJFrame方法,这个方法是用来构建整个窗体的样式。所有的监听和重绘等功能在这个窗体展开。
(二)先从监听来说,我设了两个监听。
【】一个WestGraphListener类继承了MouseListener和MouseMotionListener来实现鼠标监听和鼠标拖动监听,关于鼠标系列的监听器,只要记住关键点就是,它用来监听容器类,时刻记住这点,你要用它监听什么,就把什么绑上这个监听器,因为我要实现的是在画布上作画,即我规定鼠标监听器的作用范围是画布,所以

//添加画布的鼠标监听器
WestGraphListener westGraphListener=new WestGraphListener(graphicsBrush,buttonGroupPen,jButtonPen,arrayList);
jPanelDraw.addMouseListener(westGraphListener);
jPanelDraw.addMouseMotionListener(westGraphListener);

其中传过去的参数这样来理解,我在监听器上我要用到的信息是什么。
1)我需要用到的重要信息自然是画笔,可以根据鼠标的动作在屏幕上留下痕迹的东西,因为鼠标的不断移动变化,自然不能将什么东西绑在鼠标上,所以GUI提供了一种画笔,你要在什么容器上面作画,你就从什么容器上获取画笔

//从画布获取画笔
Graphics graphicsBrush=jPanelDraw.getGraphics();

2)比如我想实现不同画笔的实现,那么我就要得到我所点击的西边区域那些画笔的信息,本来要得到那些画笔的信息,也应该在那些按钮上绑定监听器,但是因为按钮组有强大的可以获取到相应信息的功能

ButtonModel buttonModel=buttonGroupPen.getSelection();
command=buttonModel.getActionCommand();

所以就不需要绑定监听器了,直接把按钮组当做参数传给监听器就可以了,但是其他的实现还是需要单选按钮绑上监听器,这里先不说。
【】另一个SouthColorListener类继承了ActionListener类来实现事件监听,关于事件监听记住关键点,这是监听按钮组件的,前面说过因为单选按钮的按钮组有强大的获取单选按钮的事件信息,不过也可以给单选按钮绑上事件监听器来实现其他的动作,比如下面子面板(各个画笔的粗细的选项面板)的切换。
嗯,南边区域的颜料盘也是一个个按钮组成的,所以要实现颜色的切换,就可以给这些按钮绑上事件监听器

SouthColorListener southColorListener=new SouthColorListener(jButtonPen);
//以及写在循环里的绑定
jButtonPigment.addActionListener(southColorListener);

这个事件监听器的实现代码比较少

public class SouthColorListener implements ActionListener{
    public JButton jButtonPen;
    public SouthColorListener(JButton jButtonPen) {
        this.jButtonPen=jButtonPen;
    }
    public void actionPerformed(ActionEvent e) {
        //获取事件源
        JButton jButtonPigment=(JButton)e.getSource();
        Color color=jButtonPigment.getBackground();
        jButtonPen.setBackground(color);
    }
}

(三)各种画笔功能的实现
数一下,可以发现我们的西边区域的画笔有16个格子,即16种画笔要实现,可以用if else来进行画笔的选择,不急,可以先把画笔划分到几个不同的鼠标监听里
1)先是MouseListener类的mouseReleased方法,在这方法里,什么图形是在鼠标释放的瞬间形成的?直线,矩形,椭圆,圆矩形还有取色的功能,至于具体的实现,可以查阅API中graphics类下的各种方法实现,在下一章博客我也会把完整的代码贴出来。
不过可以说一下其中取色器的实现,取色器里用到了robot机器人类,做到自动获取屏幕中信息的功能,用机器人类可以实现远程监听呢。

if (command.equals("jpg-4")) {
//取色器的实现
try {
Robot robot=new Robot();
//截屏
//创建一个矩形区域对象
Rectangle rectangle=new Rectangle(e.getXOnScreen(), e.getYOnScreen(), 1, 1);
BufferedImage bufferedImage=robot.createScreenCapture(rectangle);
//获取图片像素点的颜色
int c=bufferedImage.getRGB(0, 0);
Color color=new Color(c);
//把颜色设置到颜料盘的JButtonPen上
jButtonPen.setBackground(color);
} catch (AWTException e1) {
e1.printStackTrace();
}
}

2)然后是MouseMotionListener类的mouseDragged(拖动)方法,什么图形是鼠标一边拖动一边形成的呢?橡皮擦,铅笔,刷子,喷枪。
这几个图形用到的方法其实都是画直线的方法,只是比画直线多了一些技巧,比如喷枪的实现:

if (command.equals("jpg-8")) {
//绘制喷枪
graphicsBrush.drawLine(x2, y2, x2, y2);
//在当前点周围绘制更多的随机点
for (int i = 0; i < 30; i++) {
int x_p=random.nextInt(21)-10;
int y_p=random.nextInt(21)-10;
graphicsBrush.drawLine(x2+x_p, y2+y_p, x2+x_p, y2+y_p);
}
}

(四)不算最后的实现:重绘
重绘的原理即是重写JFrame类里的paint方法,我们计算机的存储有三种,硬盘,内存,闪存(CPU)。内存存电脑正在运行的数据,闪存存屏幕上出现的数据。你创建的窗体对象,缩小了再放大,关于它的属性大小标题什么的原封不动的重现在屏幕上,但你在这个窗体对象上画的画,没有重现,为什么?因为你创建的窗体是对象,内存存了它的数据,但你画的东西都只是临时的,内存并没有存下,所以CPU没法从内存里得到你画下的东西的数据,然后再重现在屏幕上。
你重写一个继承JFrame类里的paint方法:

//画布设置
JPanel jPanelDraw=new JPanel() {
//重绘功能
public void paint(Graphics graphicsBrush) {
super.paint(graphicsBrush);
for (int i = 0; i < arrayList.size(); i++) {
//获取对象
MyShape myShape =arrayList.get(i);
myShape.draw(graphicsBrush);
}
}
};

为什么要把paint方法放在画布里?因为你重绘要用到的画笔应该是来自画布的,保持了作画和重绘的一致性。
自然,要存。用什么存?

//创建全局数组队列
ArrayList<MyShape> arrayList=new ArrayList<MyShape>();

用数组队列来存,存下一个个被封装了的图形对象MyShape,然后调用MyShape里的draw方法,将一个个对象重新画出来。在MyShape类里面,封装好一个个图形要用到的坐标数据和颜色以及画笔的粗细。

public abstract class MyShape {
public int x1,x2,y1,y2,size;
public Color color;
public MyShape(int x1, int x2, int y1, int y2,Color color) {
this.x1=x1;
this.x2=x2;
this.y1=y1;
this.y2=y2;
this.color=color;
}
public MyShape(int x1, int x2, int y1, int y2, Color color, int size) {
this.x1=x1;
this.x2=x2;
this.y1=y1;
this.y2=y2;
this.color=color;
this.size=size;
}
public abstract void draw(Graphics graphicsBrush);
}

再用一个个子类来继承这个抽象类,来实现各种图形的绘制和重绘,做到封装的效果,比如直线类:

public class MyLine extends MyShape{
public MyLine(int x1, int x2, int y1, int y2, Color color) {
super(x1, x2, y1, y2,color);
}
public MyLine(int x1, int x2, int y1, int y2, Color color, int size) {
super(x1, x2, y1, y2, color, size);
}
public void draw(Graphics graphicsBrush) {
graphicsBrush.setColor(color);
((Graphics2D) graphicsBrush).setStroke(new BasicStroke(size));
graphicsBrush.drawLine(x1, y1, x2, y2);
}
}

整体的画板实现思路就是这样了,画板->监听->多图形实现->重绘。完整的代码在下一章贴出来,总共有九个类,类多不要紧,只要业务实现逻辑对就行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值