在前面的一篇博客中发表了一篇关于简单画图板的实现的博客,那个画图板的功能不多,而且界面不美观,
最重要的缺陷在于当我们最小化画图板后再最大化的时候,之前我们画的所有的东西都不见了,主要原因是当 我们再次最大化画板的时候系统会自动调用画板所继承的父类中的paint()方法,从而将整个画板都重新初始化的绘制了一下,所以我们原来的东西就不见了,所以我们如果想实现不管怎么操作画板(移动,最小化,最大化)绘制的图片还存在画板上的话,首先是定义一个队列来保存画过的图形,然后就是要重写画图面板的paint()方法(这里要注意的是:一定要重写我们绘画的区域的paint()方法,比如是JFrame的的重写JFrame的paint()方法,如果是JPanel的就重写JPanel的paint() 方法,要是paint()方法的位置写错了的话,这次还有改进的是界面的美观化,仿造了Windows系统下的画图板的界面,虽然还离得比价远,但是比原先的要美观了许多,以下将具体分析代码和所实现的功能,以及自己在实现过程中曾经遇到的问题
1:画图板界面的设计,主要分为两个区域(north_Panel),一个是功能选择区(包括颜色,形状的选择,橡皮擦,保存图片,打开图片(这两个功能尚未实现,会在后面继续完善),清空画图区所画的图片,还有显示所选颜色的显示,另外一个区域就是画图区(south_Panel),总体的显示如下图:
先说颜色选择区域,使用的全是按钮组件,在单选颜色区给每个按钮设置背景颜色,并且使用setBounds()方法(必须先将north_Panel的布局不要成默认的,操作如下north_Panel.setLayout(null)将每个按钮安放到指定的位置,具体代码如下(由于其颜色按钮的代码都一样,只取一部分代码):
JButton color1 = new JButton();
JButton color2 = new JButton();
JButton color3 = new JButton();
.......
color1.setBounds(700, 40, 25, 25);
color1.setBackground(Color.blue);
color2.setBounds(727, 40, 25, 25);
color2.setBackground(Color.black);
color3.setBounds(752, 40, 25, 25);
color3.setBackground(Color.gray);
.......
其他的按钮都是使用相同的方法,只是不是给每个按钮设置背景颜色,而是给每个按钮设置一张背景图片,本人画图板的按钮的图片都是截图,然后要保存在所建的工程下面如图:
插入到具体按钮下的代码如下(只取一部分):
JButton type1 = new JButton();
type1.setBounds(320, 20, 39, 37);
JButton type2 = new JButton();
type2.setBounds(360, 20, 39, 37);
......
ImageIcon Type_icon1 = new ImageIcon("type1.jpg");
ImageIcon Type_icon2 = new ImageIcon("type2.jpg");
........
type1.setIcon(Type_icon1);
type2.setIcon(Type_icon2);
此处需要注意的时候就是ImageIcon()的参数是一个字符串,必须保持与保存在工程文件中的图片的名字一样
画图板的north_Panel的最左边是一个自己定义的面板colorUI,用来实现显示所选的颜色,初始默认为黑色,代码如下:
JPanel colorUI = new JPanel();
colorUI.setBounds(920, 30, 50, 50); // 显示所选的颜色的面板,初始化为black,
colorUI.setBackground(Color.black);
north_Panel.add(colorUI);
功能区域下面是画图区域,定义背景颜色为白色,代码如下:
south_Panel.setBackground(Color.white);
整个窗体使用的是BorderLayout布局管理,起初设置north_Panel的大小,然后将south_Panel布局在中间(就默认充满剩余的区域了)代码如下:
north_Panel.setPreferredSize(new Dimension(0, 150)); //窗体外的组件的大小设置只能用setPreferredSize
//(0,150)表示只要设置宽度就行了,长度默认
this.add(north_Panel, BorderLayout.NORTH);
this.add(south_Panel, BorderLayout.CENTER);
下面介绍每个按钮的功能背后是如何实现的:
1 .给每个按钮设置一个命令,就相当于点击后产生的命令,示例代码如下:
color1.setActionCommand("blue");
color2.setActionCommand("black");
........
2.创建一个动作监听器 ,用来监听每个动作,代码如下:
public class DrawPanelActionLis implements ActionListener {
public void actionPerformed(ActionEvent e);
}
3.给每个按钮加上 动作监听器,这就要在主类中生成一个动作监听器对象,然后给每个按钮加上代码如下:
DrawPanelActionLis dPAc = new DrawPanelActionLis();
color1.addActionListener(dPAc);
color2.addActionListener(dPAc);
.........
4.在动作监听器内实现ActionListener接口的方法,通过e.getActionCommand()方法获取各个按钮的命令,通过判断来实现点击按钮后所实现的操作,示例代码:
public void actionPerformed(ActionEvent e) {
colorCommand = e.getActionCommand(); //获取命令
if(colorCommand.equals("blue")) { //进行判断
color = Color.blue; //进行所选颜色的赋值
jp1.setBackground(color); //将选中的颜色设置为“所选颜色”面板的背景颜色
}else if(colorCommand.equals("black")) {
color = Color.black;
jp1.setBackground(color);
}else if(colorCommand.equals("gray")) {
color = Color.gray;
jp1.setBackground(color);
}else if(colorCommand.equals("red"))
.........
//点击更多颜色时会弹出调色板,可以选择颜色,调色板的使用方法代码如下:
else if(colorCommand.equals("moreColor")) {
color = JColorChooser.showDialog(null, "请选择你所需的颜色",Color.black);//这是调色板的的一些信息
jp1.setBackground(color); //也会将选择的颜色显示到“所选颜色”面板上
}
效果如下:
//点击相应按钮能实现相应的操作的方法都是写在此方法内,在些按钮面有个“清空图片”的操作,本人
//使用的是用画布背景色画一个充满画布的满圆来覆盖原来的图片,代码如下:
clearAllCommand = e.getActionCommand();
if(clearAllCommand.equals("clear")) {
//清空图片 ,
g.setColor(Color.white);
g.fill3DRect(0, 0, 1000,750,true);
}
这里就存在问题了,在我们给“所选颜色”面板(jp1)设置背景颜色和画满圆时,在DrawPanelActionLis里面没有画布对象g(g是在前面向系统获取画画权限所生成的(Graphics g = south_Panel.getGraphics(); // 这样才可以在south_Panel上进行绘图),所以就要进行传参的操作代码如下:
JPanel colorUI = new JPanel();
Graphics g = south_Panel.getGraphics();
DrawPanelActionLis dPAc = new DrawPanelActionLis(colorUI, g);
然后在DrawPanelActionLis中就要重载 构造方法:
private JPanel jp1;
private Graphics g;
public DrawPanelActionLis(JPanel jp1,Graphics g) {
this.jp1 = jp1;
this.g = g;
}
接下来就是获得画图点的坐标了 我定义的是类MymouseAdlistener继承抽象类 MouseAdapter 取出MouseAdapter中 的方法
public void mousePressed(MouseEvent e) {};
public void mouseReleased(MouseEvent e) {};
来获取点的坐标,并通过DrawPanelActionLis的对象来获取所选的颜色和形状(这就首先需要在DrawPanelActionLis中定义两个返回所选的颜色和图形形状的方法):
//定义返回所选颜色的方法
private Color color;
public Color getColor() {
return color;
}
//定义返回所选的图形
private int shapeStyle; //将对应的图形用数字表示
public int getShape() {
return shapeStyle;
}
接下来需要创建一个MymouseAdlistener的对象然后将south_Panel添加到MouseAdapter(其中包含三个监听器,自由选择)中的MouseListener监听器下面,代码: MymouseAdlistener myadlistener = new MymouseAdlistener(g, dPAc); south_Panel.addMouseListener(myadlistener); 然后就是绘图了 ,首先我先定义了一个Myshape类 ,里面有一个draw()方法,判断type的值来绘制不同的图形(前面说明已将各种图形用数字代替了),在MymouseAdlistener中通过DrawPanelActionLis的对象调用getShape() 和 getColor() 方法返回颜色和图形形状选择,再在MymouseAdlistener中创建Myshape对象调用Myshape中的draw()方法,具体代码如下:
import java.awt.Color;
import java.awt.Graphics;
/**
* 定义图形类
* @author sony
*
*/
public class Myshape {
private int type;
private int x1,x2,y1,y2;
private Graphics g;
private Color color;
public Graphics getG() {
return g;
}
public void setG(Graphics g) {
this.g = g;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
public void setX2(int x2) {
this.x2 = x2;
}
public int getX2() {
return x2;
}
public void setY1(int y1) {
this.y1 = y1;
}
public void setY2(int y2) {
this.y2 = y2;
}
public int getY1() {
return y1;
}
public int getY2() {
return y2;
}
public void draw() { //通过type的数值来进行判断画什么形状
if(type == 1) {
//画right 箭头
g.setColor(color); // 通过Myshape的对象shape来返回所选的图形的颜色
......
}
if(type == 2) {
//画左箭头
g.setColor(color);
......
}
......
在上面我将橡皮擦的功能设置在type=10时画的图形 我的橡皮擦比较简单就是用g.drawfillOval的方法,将填充色改成画板的背景色代码如下:
if(type == 10) {
g.setColor(Color.white); //画板的背景色为白色,所以用白色来画满圆来起到橡皮擦的作用
g.fillOval(Math.min(x1, x2), Math.min(y1, y2),Math.abs(x1-x2), Math.abs(y1-y2));
}
我们知道坐标是在MymouseAdlistener中通过
public void mousePressed(MouseEvent e) {
//得到起始点坐标
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e) {
//得到终点坐标
x2 = e.getX();
y2 = e.getY();
}
得到的,要传到Myshape类中实现画图就要用在MymouseAdlistener中定义的Myshape类的shape对象将得到的坐标送到Myshape中的x1,x2,y1,y2,中去,还要将画布对象也传过去,代码如下:
Myshape shape = new Myshape();
shape.setG(g); //把Graphics g = south_Panel.getGraphics();得到的g传到
shape.setX1(x1); //MymouseAdlistener 中然后通过shape.setG(g)传到Myshape中
shape.setY1(y1);
shape.setX2(x2); //将坐标传到Myshape 中
shape.setY2(y2);
shape.setColor(d.getColor()); //将颜色选择和图形选择传到Myshape中
shape.setType(d.getShape());
shape.draw(); //调用Myshape中的draw()方法
现在最重要的事就出现了 我们想要实现的是重绘,所以我们所要做的就是把我们已经画的图保存下来,所以我们要在MymouseAdlistener中定义一个Myshape类型的队列用来保存我们所画过的图的信息(包括颜色,图形类型)利用List的add()方法将每个shape对象添加到队列中去所以总的实现画了之后并保存下来的代码为:
List<Myshape> list = new ArrayList<Myshape>();
public MymouseAdlistener(Graphics g,DrawPanelActionLis d) { //将要用到的对象传过来
this.g = g;
this.d = d;
}
public void mousePressed(MouseEvent e) {
//得到起始点坐标
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e) {
//得到终点坐标
x2 = e.getX();
y2 = e.getY();
//把图形的信息封装到一个对象中
Myshape shape = new Myshape();
shape.setG(g);
shape.setX1(x1);
shape.setY1(y1);
shape.setX2(x2);
shape.setY2(y2);
shape.setColor(d.getColor());
shape.setType(d.getShape());
shape.draw();
list.add(shape); //队列list对象调用add()方法将当前的shape添加到队列中
}
放进去后要实现重绘的时候就要从队列中依次把每个元素取出来实现重绘所以还要定义一个返回 队列中元素的方法:
public Myshape getShape(int i) { //队列中的每一个元素都是Mysahpe 类型的
return list.get(i);
}
好!这样想实现 重绘就差一步了,我们要就只要像开头说的那样,重写我们画布区域south_Panel中的paint()方法了,这都是固定的格式,代码如下:
JPanel sorth_Panel = new JPanel() {
public void paint(Graphics g) { //这是每个组件的都有的一个固有的方法
super.paint(g); //首先要重写父类的paint()方法
for (int i = 0; i < myadlistener.list.size(); i++) { //使用循环实现每个队列中的图像的再绘制
Myshape shape = myadlistener.getShape(i); //获得队列中的元素
if (shape.getType() == 5) { //通过判断实现再绘制
g.setColor(shape.getColor()); //获得队列中的相对应元素的颜色
g.drawLine(shape.getX1(), shape.getY1(), shape.getX2(), //获取坐标,实现重绘
shape.getY2());
} else if (........) {
...... //相同的方法
}
.......
}
}
}
// myadlistener 说明: 应该定义为类的一个变量,这样才能在paint()f方法中调用 即: private MymouseAdlistener myadlistener 所以将上面south_Panel 加MouseListener处的代码改成如下:
private MymouseAdlistener myadlistener ; //这个变量可以在类里面用
myadlistener = new MymouseAdlistener(g, dPAc);
这样myadlistener就可以在paint() 方法中调用了
最后总结一下完成这个画图板后的一些收获,虽然画图板是很基本的一个小项目,但是这里面所包含的一些知识点 确是很重要的,其中各个类之间的传参就很值得我们去学习,就这么几个类就把我传晕了,基本功还不是很扎实,在传参这部分还有待加强,还有就是布局的收获也挺大的,一开始就走错路了,搞得后面就只能一直使用 setBounds()方法来摆放各种组件,都是在错误中成长的嘛!这是学java一个多月以来算是做的最久的一个小项目吧,写博客也没什么经验,里面肯定还有很多错误的地方,慢慢改进吧。还有保存和打开的功能也还没能实现,还需改进。下面是代码 运行的效果:
点击橡皮擦后擦点一部分后的效果:
点击最小画和最大化后的效果如下:
点击清空后的效果如下:
相关推荐
10. **界面设计**:良好的用户体验是必不可少的,因此需要使用布局管理器如`BorderLayout`、`GridLayout`或`BoxLayout`来组织GUI组件,并确保界面美观且易于使用。 以上就是关于“JAVA设计画图板资源管理”的一些...
在LabVIEW中,“画图”指的是使用其强大的图形化编程功能来创建各种图表和可视化界面。本节将深入探讨LabVIEW在绘图方面的应用和相关知识点。 1. **GDI+与OpenGL绘图** LabVIEW支持两种主要的绘图技术:GDI+...
总结来说,【界面换肤软件】是一个能够提升应用程序视觉吸引力的工具,它涉及到界面开发中的重绘技术,以及对MFC、Win32和C#等不同开发环境的理解与应用。通过有效的代码实现和资源管理,开发者可以轻松地为程序添加...
易语言是一种专为初学者设计的编程语言,它采用了贴近自然语言的语法,使得编程变得更加简单易懂。...同时,这也是一种提高软件界面美观度和用户体验的有效手段,对于提升软件的整体品质大有裨益。
同时,关注性能优化,比如减少不必要的重绘,使用智能指针管理内存,避免内存泄漏。 9. **构建和部署** 编译并运行你的项目,确保在所有目标平台上都能正常工作。如果需要,可以打包应用程序,发布给其他人使用。 ...
在易语言中,我们可以通过编写事件处理程序,如“画板重绘”事件,来控制画板上的内容显示。 制作进度条的关键步骤包括以下几个方面: 1. **创建画板组件**:在易语言的界面设计中,添加一个画板组件到窗体上,...
易语言是一款面向中国用户的、具有图形化编程界面的编程工具,它以其简洁的语法和丰富的内置组件,使得初学者也能快速上手。在易语言中,我们可以利用画板组件的绘图功能,实现自定义的进度条效果。 1. **画板组件...
对图形进行缓存,减少计算和重绘开销;使用智能更新策略,只传输变化的部分,降低带宽消耗。 总结,“DrawMeWCF”项目展示了WPF和WCF在图形绘制领域的强大潜力,通过它们的结合,可以构建出功能强大、交互丰富的...
此外,图形绘制逻辑也需在此阶段开发,包括处理鼠标事件(按下、移动、释放),以及重绘事件。 #### 第三部分:双缓冲绘图 双缓冲技术是提升绘图性能的关键,通过在后台缓存绘制结果,避免屏幕闪烁,提供更平滑的...
需要注意的是,频繁的重绘可能会导致性能问题,因此可以使用UpdateWindow和InvalidateRect函数的组合来控制重绘的频率。 对于"自定义的类可移植"这一点,这意味着我们需要设计类时考虑到代码的可重用性和可扩展性。...
例如,通过合理使用缓存、减少不必要的重绘等手段,保证程序的流畅运行。 在实际开发过程中,除了掌握上述基础知识,还需要对易语言的API有深入理解,包括控件的操作、颜色处理、图形绘制等。同时,对于美工设计有...