画板算是我在学习java过程中第一个完成的迷你项目,现在总结一下它。
画板实现的第一步就是定义一个JFrame,作为放置按钮以及画布的容器,同时设置它的相关属性:
setTitle("画板");
setSize(600, 600);
this.setDefaultCloseOperation(3);
this.setResizable(false);
this.setLocationRelativeTo(null);
// this.setLayout(new FlowLayout());
this.setLayout(null);
this.setBackground(Color.WHITE);
接下来定义一个JPanel,并设置它在JFrame中的坐标位置,以及它的行列数目
JPanel panel = new JPanel();
panel.setBounds(0, 0, 600, 100);
panel.setBackground(Color.WHITE);
panel.setLayout(new GridLayout(2, 5));
this.add(panel);
drawpanel.setBounds(0, 100, 600, 500);
drawpanel.setBackground(Color.WHITE);
this.add(drawpanel);
之后在面板上添加相应的按钮,我制作的按钮有九个:
JButton btn = new JButton("直线");
btn.setActionCommand("Line");
panel.add(btn);
JButton btn1 = new JButton("曲线");
btn1.setActionCommand("Curve");
panel.add(btn1);
JButton btn2 = new JButton("颜色");
btn2.setActionCommand("Color");
panel.add(btn2);
JButton btn3 = new JButton("圆");
btn3.setActionCommand("Circle");
panel.add(btn3);
JButton btn4 = new JButton("矩形");
btn4.setActionCommand("Rectangle");
panel.add(btn4);
JButton btn5 = new JButton("填充圆");
btn5.setActionCommand("FillCircle");
panel.add(btn5);
JButton btn6 = new JButton("填充矩形");
btn6.setActionCommand("FillRectangle");
panel.add(btn6);
JButton btn7 = new JButton("橡皮");
btn7.setActionCommand("Eraser");
panel.add(btn7);
JButton btn8 = new JButton("图片");
btn8.setActionCommand("Picture");
panel.add(btn8);
写好面板上的内容之后,就可以添加动作监听器了,也就是作为点击按钮之后的事件处理动作
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Color")) {
color = javax.swing.JColorChooser.showDialog(null, "颜色选择器",
Color.BLACK);
System.out.println("你选择的颜色是" + color);
} else {
Item = e.getActionCommand();
System.out.println("你选择的按钮是:" + Item);
System.out.println("现在队列中有" + DrawListener.stl.size()
+ "个对象");
}
}
};
下面给每个按钮加上这样的监听器,这样每次点击发生时都会调用到相应的动作
btn.addActionListener(al);
btn1.addActionListener(al);
btn2.addActionListener(al);
btn3.addActionListener(al);
btn4.addActionListener(al);
btn5.addActionListener(al);
btn6.addActionListener(al);
btn7.addActionListener(al);
btn8.addActionListener(al);
记得在添加按钮后设置整个面板可见,有一次我放错了可见的设置位置,纠结了一阵
setVisible(true);
此时,还要给之前定义的JPanel加上鼠标监听器,因为我们画图像的时候是在画布上画的,也就是说要对你的鼠标点击以及拖动做出反应。这里要强调一点,必须把drawpanel也传过去,否则绘制的时候会出现坐标偏差,因为系统默认是以JFrame为坐标基准的
DrawListener dl = new DrawListener(this,drawpanel);
drawpanel.addMouseListener(dl);
drawpanel.addMouseMotionListener(dl);
此时,整个面板的定义结束,我们接下来要编辑的就是监听器类
首先定义一个监听器的构造函数,用于在JFrame中实例化对象,并将JFrame以及Drawpanel传过来进行操作
public DrawListener(DrawFrame df,JPanel drawpanel){
this.df = df;
g = drawpanel.getGraphics();
this.drawpanel = drawpanel;
}
其中g是一个画布对象,即指你画在画布上的那个东东,可以通过捕获g来设置将要绘制的图像的颜色、形状等。
做完了这些,就要定义鼠标的按下和释放时要执行的动作了
public void mousePressed(MouseEvent e){
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e){
x2 = e.getX();
y2 = e.getY();
g.setColor(df.getColor());
color = g.getColor();
if(df.getItem().equals("Line")){
g.drawLine(x1, y1, x2, y2);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
stl.add(shape);
}
if(df.getItem().equals("Circle")){
g.drawOval(x1, y1, x2, y2);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
stl.add(shape);
}
if(df.getItem().equals("Rectangle")){
g.drawRect(x1, y1, x2, y2);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
stl.add(shape);
}
if(df.getItem().equals("FillCircle")){
g.fillOval(x1, y1, x2, y2);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
stl.add(shape);
}
if(df.getItem().equals("FillRectangle")){
g.fillRect(x1, y1, x2, y2);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
stl.add(shape);
}
if(df.getItem().equals("Picture")){
image = Toolkit.getDefaultToolkit().getImage ("C://workspaces//JavaLessons//src//cn//wx//Excise6//leaf.jpg");
g.drawImage(image, x1, y1, 100, 100, df.getBackground(), df);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
stl.add(shape);
}
}
上方括号内的是图片的绝对路径,需要时候自己写入即可,我上网查了很多图片导入的方法,最后总结出了这个,应该是最简单的图片导入了吧,或者大家可以把图片放在文件目录下,通过相对路径导入。其中特别要注意的是,图片导入的时候一定要把绝对路径的\全部换做//,我当时搞这个抑郁了好一会。
接下来是鼠标拖动时的动作,也就是点击画曲线
public void mouseDragged(MouseEvent e){
x2 = e.getX();
y2 = e.getY();
g.setColor(df.getColor());
if(df.getItem().equals("Curve")){
g.drawLine(x1, y1, x2, y2);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, x2, y2);
stl.add(shape);
x1 = x2;
y1 = y2;
}
}
下面是点击按钮后拖动鼠标会执行的动作,也就是橡皮
public void mouseMoved(MouseEvent e){
x2 = e.getX();
y2 = e.getY();
if(df.getItem().equals("Eraser")){
g.setColor(Color.WHITE);
g.clearRect(x1, y1, 100, 100);
Shapes shape = new Shapes(color, df.getItem(), x1, y1, 100, 100);
stl.add(shape);
x1 = x2;
y1 = y2;
}
}
到此为止,一个简易的画板就算是完成了,接下来要进行的是画板的重绘,也就是说现在的画布对象只是暂时可见的,一次最小化就会完全消失,因为窗口的每一次弹出都会自己按照代码重新实现,之前所画的东东如果不保存就一定不会再出现,其实这个实现起来很简单,但当时我不理解原理,也弄得很懵懂。首先是定义一个队列,从而能够自动增长存储画布元素
public interface queueinter<E>{
//添加对象
public void add(E e);
//根据索引返回对象值
public E get(int index);
//得到队列长度
public int size();
//在指定位置插入一个对象
public void insert(int index,E e);
//删除一个对象,并返回值
public E delete(int index);
//在队列的尾部添加另一队列的所有对象
public void addAll(STList<E> list);
以上是定义了一个接口来规范接下来要写的方法名、返回值、参数类型等,下面是写一个类实现这些方法
public class STList<E> implements queueinter<E>{
private Object [] obl = new Object[0];
private int size = obl.length;
//添加对象
public void add(E e){
Object [] temp = new Object[obl.length+1];
temp[obl.length] = e;
System.arraycopy(obl, 0, temp, 0, obl.length);
obl = temp;
}
//根据索引返回对象值
public E get(int index){
E e = (E) obl[index];//转型
return e;
}
//得到队列长度
public int size(){
return obl.length;
}
//在队列的尾部添加另一队列的所有对象
public void addAll(STList<E> list){
Object [] temp = new Object[obl.length+list.size()];
System.arraycopy(obl, 0, temp, 0, obl.length);
System.arraycopy(list, 0, temp, obl.length, list.size());
this.size = obl.length+list.size();
obl = temp;
}
//在指定位置插入一个对象
public void insert(int index,E e){
Object [] temp = new Object[obl.length];
System.arraycopy(obl, index, temp, 0, obl.length-index);
for(int i=index;i<obl.length;i++){
obl[i] = null;
}
obl[index] = e;
this.size++;
System.arraycopy(temp, 0, obl, index+1, temp.length);
}
//删除一个对象,并返回值
public E delete(int index){
E e = (E) obl[index];
for(int i=index;i<obl.length;i++){
obl[i] = obl[i+1];
}
this.size--;
return e;
}
public void show(){
System.out.println(obl);
}
同时,定义一个名为Shapes的类,存储所画的图形信息
public class Shapes {
private int x1,y1,x2,y2;
private Color color;
private String item;
public Shapes(Color color,String item,int x1,int y1,int x2,int y2){
this.color=color;
this.item=item;
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
}
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
public int getY1() {
return y1;
}
public void setY1(int y1) {
this.y1 = y1;
}
public int getX2() {
return x2;
}
public void setX2(int x2) {
this.x2 = x2;
}
public int getY2() {
return y2;
}
public void setY2(int y2) {
this.y2 = y2;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
所有的这些做好后,就是要在JFrame的绘制方法中加入图片已保存信息的输出,也就是画出与之前所画的同样的图形,注意将重绘的方法写在drawpanel里面,因为这样就能够保证每一次重绘画布的时候我们的图形能够在上面显示
JPanel drawpanel = new JPanel() {
public void paint(Graphics g) {
super.paint(g);
if (null != DrawListener.stl) {
// 取出队列中保存信息
for (int i = 0; i < DrawListener.stl.size(); i++) {
Shapes sp = DrawListener.stl.get(i);
Color c = sp.getColor();
if (sp.getItem().equals("Line")|| sp.getItem().equals("Curve")) {
g.setColor(c);
g.drawLine(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
} else if (sp.getItem().equals("Rectangle")) {
g.setColor(c);
g.drawRect(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
} else if (sp.getItem().equals("Circle")) {
g.setColor(c);
g.drawOval(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
} else if (sp.getItem().equals("FillCircle")) {
g.setColor(c);
g.fillOval(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
} else if (sp.getItem().equals("FillRectangle")) {
g.setColor(c);
g.fillRect(sp.getX1(), sp.getY1(), sp.getX2(), sp.getY2());
} else if (sp.getItem().equals("Eraser")) {
g.setColor(c);
g.clearRect(sp.getX1(), sp.getY1(),sp.getX2(),sp.getY2());
} /**else if (sp.getItem().equals("Picture")) {
image = Toolkit.getDefaultToolkit().getImage("C://workspaces//JavaLessons//src//cn//wx//Excise6//leaf");
g.drawImage(image, sp.getX1(), sp.getY1(), 100, 100,df.getBackground(),df);
}*/
}
}
}
};
起初完成后,我的图片重绘是有问题的,老师说在图片重绘时不能用绝对路径,可以将它放在代码所在的目录下进行引用,即可实现重绘。
通过这次的画板绘制我学习到了很多,很多细微的东西之前只是在听,觉得自己懂了,但是实际操作起来还是有一定难度的,一些小细节不注意就会出错,在编写代码时一定要注意自己能够调错,遇到不理解的错误可以在报错的地方多加几条输出语句查看整个过程是否如预想一般地进行,虽然这可能都不能算是写出一个项目,只是最简单的实现而已,相信有了这一点一滴的积累,我今后的学习会更加顺利~~~~~
艾儿~~
分享到:
相关推荐
4. **事件处理**:在易语言中,我们需要监听窗口或画板的特定事件,比如“窗口初始化”或“画板重绘”。在这些事件的处理函数中,我们可以调用绘制函数来更新进度条的显示。 5. **进度更新**:当程序执行的任务进度...
在易语言中,我们可以通过编写事件处理程序,如“画板重绘”事件,来控制画板上的内容显示。 制作进度条的关键步骤包括以下几个方面: 1. **创建画板组件**:在易语言的界面设计中,添加一个画板组件到窗体上,...
易语言画板自绘源码,画板自绘,标尺子程序_绘制标尺刻度,恢复鼠标状态,无拖动时激活恢复,刻度区重绘,客户区重绘,二级缓冲绘制,客户区刷新,选中辅助线,高亮辅助线,拖动辅助线,客户绘制的图形,GetProp,SetRect,SetProp,...
4. **内存位图**:为了提高效率和避免频繁的屏幕重绘,通常会使用内存位图来保存当前画板的状态。当需要更新画板时,将内存位图的内容复制到窗口上,而不是重新绘制所有图形。 5. **文本处理**:除了图形绘制,自绘...
在易语言中,开发者需要理解窗口消息机制,比如WM_PAINT消息,这是窗口需要重绘时发送的消息。收到该消息后,开发者需要在OnPaint事件中执行自绘代码,确保界面的更新。同时,界面的绘制应考虑效率,避免不必要的重...
3. 事件响应:设置画板的绘图事件,如WM_PAINT消息,当需要更新画布时,调用绘制逻辑函数进行重绘。 4. 数据管理:存储列表项的数据结构,如数组或列表,用于驱动绘图逻辑。 5. 用户交互:处理鼠标和键盘事件,使...
1. **自绘机制**:自绘的核心在于响应窗口的重绘事件,通过`窗口过程`函数捕获并处理这些事件。在易语言中,你需要覆盖默认的绘制行为,使用`画图`命令绘制列表框的背景、条目和选中状态。 2. **列表重画**:在列表...
在这个“易语言画板自绘列表”主题中,我们主要讨论的是如何在易语言环境下创建和操作自绘列表,这涉及到多个核心概念和技术。 首先,**画板**是编程中常见的一种图形用户界面(GUI)组件,它允许程序员在上面进行...
在这个源码中,开发者需要实现OnPaint事件,该事件会在控件需要重绘时被触发,用于执行实际的绘图操作。 2. **图形API的使用**:易语言提供了丰富的图形API,如画线、画圆、填充颜色等。这些函数可以用来在控件上...
6. **图形缓存**:掌握如何利用内存中的位图进行图形缓存,提高界面重绘性能。 7. **界面交互设计**:设计并实现用户与自绘界面的交互逻辑,如按钮点击、拖放操作等。 8. **源码分析**:通过对提供的源码进行分析...
在VS2015环境下,利用MFC框架实现的一款高仿“画图”工具,实现绝大部分功能甚至更多创新点。(注释超详细) 实现了点、直线、曲线、折线、矩形、圆形、多边形等等形状,并且具有区域限制、鼠标捕捉等功能;...
2. **事件驱动编程**:易语言是基于事件驱动的,源码中会包含各种事件处理函数,如`鼠标点击事件`、`窗口重绘事件`等。这些事件触发相应的绘图操作,实现动态效果。 3. **坐标系统和绘图模式**:了解易语言中的坐标...
1. **注册消息处理**:首先,我们需要注册WM_PAINT消息,当系统需要重绘列表框时,会发送这个消息。在易语言中,这通常通过`窗口过程`或`消息过滤`函数实现。 2. **初始化画笔和刷子**:在自绘开始前,我们需要设置...
2. **绘制列表项**:在画板的重绘事件中,我们需要遍历数据源,根据每一项数据的内容和格式,在画板上进行绘制。这可能涉及到字符串格式化、字体设置、颜色选择等细节。 3. **滚动处理**:为了实现滚动功能,需要...
在易语言中,画板通常会有一个与之关联的事件,例如“画板重绘”事件,当画板需要更新时(如滚动条移动),这个事件会被触发。在这个事件处理程序中,我们会根据滚动条的位置来决定应该在画板上显示哪一部分的图片。...
6. **优化性能**:自绘可能会带来额外的性能开销,因此在实现自绘编辑框时,需要注意尽可能减少不必要的重绘,例如使用更新区域或者双缓冲技术来提高效率。 7. **兼容性与扩展性**:自绘编辑框可能需要考虑与其他...
易语言中的事件处理是编程的核心部分,比如"画板重绘"事件,当画板需要更新时,会触发这个事件,我们在这里编写绘制列表的代码。此外,还有"鼠标点击"事件,可以用来处理用户的交互,如选择列表项。 再者,要掌握...
- 使用离屏渲染优化,避免在屏幕更新时频繁的重绘操作。 - 如果可能,可以采用OpenGL或Metal进行更底层的图形处理,提升性能。 11. **测试与适配**: - 在不同尺寸和分辨率的设备上进行测试,确保界面适应性和...
3. 处理绘图事件:在画板的"画板重绘"事件中,首先清空画板(通常用白色填充),然后根据需要调整画笔的颜色、透明度等属性。接着,使用"绘制文本"命令在画板的指定位置绘制标签的内容。 4. 实现透明效果:透明度...