- 浏览: 5041 次
- 性别:
总结
----------关于画图板
花了将近一个学期的时间,我的画图板也终于是在小部分上已经完工了,至少,他看上去已经是一个画图板了,虽然还有很多功能需要我去完善。
在制作这个画图板的时候,我当然是毫无疑问的遇到了许许多多的问题,而这个总结也是从另一方面对这些问题进行一些阐述吧!也可以算是一个大纲吧!!
首先,想要制作一个画图板,最基本的窗体是少不了的了,这个就是javax.swing.JFrame的顶级容器。
代码如下:
javax.swing.JFrame jf = new javax.swing.JFrame;
然后就是一系列对窗体功能的添加和设定:
他的标题
this.setTitle("画图板");
他的大小
this.setSize(FRAME_WIDTH, FRAME_HEIGHT);
关闭时执行的操作
this.setDefaultCloseOperation(3);
位置
this.setLocationRelativeTo(null);
等等这些能够添加的很多,但是现在只用这些就能让他形成最初的界面,之后的美化可以再继续的进行,甚至可以为他的边框进行自己的设置等等。
当然,在这之中,曾经最让我头疼的就是他的布局了。
但是最重要的是必须要将这个窗口设置为可见,什么都能少就是这个不能少。
代码如下:
This.setVisible(true);
然后,我觉得排在之后的就要是给他加上一个菜单栏了,而实现菜单栏的话,就需要用到一个数组。
在对数组的理解中,数组可以分为多维数组,这里可以是一维的,代码如下;
Object [][]Array=new Object[i][j];
这个定义方法之中需要给数组添加上一定的大小,而i,j就是他们的长度和宽度。
当然还有别的方法,而像我们在菜单栏中所需要用到的数组就是用另外一个方法来获得的,
代码如下:
String [][]Array1={“”};在这里,我们可以添加任意数量的字符串,有多少就加多少,但是一定要用双引号将他们括起来;
String [][]Array2={{“”}{“”}};在这里,很容易发现我使用了三个大括号,没错,这就代表的是这个数组是一个二维数组的定义,当然,大括号的数量并不是说是局限于三个,只是内部的大括号代表多维数组内部的字符串。
在这里我可以用表格来说明一下二维数组的图形来想象一下多维数组的概念。在二维数组中,或者是在数组中,有下标这样一个概念,顾名思义,下标的意思就是标记每一个数组每一个数字,或者字符串,又或者是其他的位置。但是,需要的注意的是,下标是从0开始的。下面我将用i和j来说明一下这个下标。
0 1 2 3 j
1
2
3
4
5
i
如表格中所见,一个数组下标的表示方法Array[i][j];
这里是使用数组的方法。
这样,使用一个数组就可以很轻松的将所需要的命令加入到菜单栏中去了。
在我们使用菜单栏的时候,我们需要用到一下三个类:
1.javax.swing.JMenuBar;
2.javax.swing.JMenuItem;
3.javax.swing.JMenu;
其中,第一个类是创建一个菜单栏,也就是载体;第二个类是给他们加入命令,第三个类是加入载体中的类似于容器的东西。
一个画图板之所以要叫做一个画图板就是因为他能够画图,这也就是下面的代码的核心了。
首先,为了能够好好的画图,我们需要的是一个类似于我们电脑上画图板左边那一栏的图标还有下面那一栏的颜色选项,这两者都是必不可少的。而这两者就都在一个叫做面板的东西上了。在JAVA中,面板需要使用到的类就是java.swing.JPanel。这是一个作为容器的东西,也就是我们放那些菜单栏的选项的地方,这个类所形成的面板也是放在窗体上的,但是他更利于我们对窗体上的分类摆放。
代码如下:
java.swing.JPanel jp=new java.swing.JPanel();
这样,我们就随时能够在jp的对象,也就是面板上添加我们所需要的东西了。
现在,我们拥有了我们放东西的地点,接下来就是放东西了。
首先,是我们左边的选择画什么图形的工具栏。
而为了方便我们的区分和选择,我们将他重新以一个类的形式进行书写,也就是ToolPanel的一个类(这个类是我们自己定义的,和JAVA程序自带的类没有任何的关系)。
在工具栏中,我们会发现有一个一个小的按钮,这些虽然都是按钮,但是和菜单栏的按钮却是不一样的,他们是JAVA中java.swing.JRadioButton中的,也就是按钮类。我们使用这个类可以给面板(JPanel)上添加上一个一个的按钮,而且可以对他们的大小和位置进行设定,这个不进行详细说明,我们需要的说明的是我们在对这些按钮添加图片的方法。因为,我们刚开始创建一个按钮对象之后,这是一个空的,也就是什么都没有在上面的,我们不知道他表示的是什么意思,事实上他们也没有任何的意义,他们只是一个按钮,而他们的意义需要我们给他们添加上,可以是文字也可以使一个图片。
代码如下:
JRadioButton jb = new JRadioButton();
this.add(jb);
但是,我们很容易发现,如果只是一个一个的按钮的话,我们很难去管理,但是恰恰一个画图板的按钮还并不少,所以,这个时候我们就需要一个java.swing.ButtonGroup的类来替我们对这些按钮进行管理。
代码如下:
ButtonGroup group=new ButtonGroup();
这样的话,我们就需要先把所有的按钮放到一起管理再进行添加了
代码如下:
Group.add(jb)
但是,就算我们这样做了, 我们会发现,我们仍然是很难快速的给我们按钮添加我们想要添加的图片或者是文字,因为一个一个的添加值是一件很麻烦的过程,这样就引入了我们需要进行循环的思想。运用一个循环,让计算机去一直按照这个循环去给按钮赋值,这样就大大缩短了我们写代码的时间,也提高的机器的效率。
代码如下:
for (int i = 0; i < 16; i++) {
// 创建按钮
JRadioButton jb = new JRadioButton();
// 设置按钮的大小
jb.setPreferredSize(new Dimension(30, 30));
// 设置图像的地址
jb.setIcon(this.change("picture/draw" + i + ".jpg"));
// 分别设置鼠标在图像上,按下时,松开时的图像
jb.setRolloverIcon(this.change("picture/draw" + i + "-1.jpg"));
jb.setPressedIcon(this.change("picture/draw" + i + "-2.jpg"));
jb.setSelectedIcon(this.change("picture/draw" + i + "-3.jpg"));
// 设按钮的动作命令
jb.setActionCommand("draw" + i);
其中,jb后中均为JButton中本身写有的方法,三种方法依次为设置鼠标在图像上,按下停留,松开时,我们想要给他加上的图像。
小技巧:为了让我们的for循环结构能够成功的运行,我们需要做的就是对我们的图片进行一些有规律性的命名,这样往往能够大大的节省我们的时间,减少我们的工作量。
在这之中,我们有点需要注意的是,在我们的电脑上,我们的对图片的命名是一样的,所以我们的电脑上存在很多相同的名称,但是由于互联网的存在,我们在登录互联网交换信息的时候,不得不想办法去避免那些相同名字的概念,所以,我们的文件的名字就被重新在互联网上进行了定义,也是URL,文件在互联网上唯一的名称。
代码如下:
public ImageIcon change(String path) {
// 将本地路径转化为网络路径
URL u = Toolpanel.class.getResource(path);
// 实例化一个ImageIcon对象,并创建一个图标对象
ImageIcon im = new ImageIcon(u);
// 返回im的值
return im;
}
完成了ToolPanel之后,就是我们的颜色那一栏了,为了方便,我们也将他写成一个单独的类,也就是ColorPanel这个类,这个类也是我们自己定义的一个类,和JAVA本身所带有的类没有任何的关系。
由于颜色按钮本身和文字和图片名有着一定的差别,虽然我们使用的都是按钮,但是,我们在对按钮添加我们想要赋予的意义的时候,就只是对他们的背景色进行的改变了,而我们想要获得的命令也就是他们的背景色。
本处代码与上面的类似,所以略过。
在我们成功的添加了工具栏和颜色栏之后,我们会发现,不管我们多么努力的去点击那些图案,我们也无法像真正的画图板一样去画一些东西。这就是我们并没有对鼠标的动作进行定义的结果。
所以,我们要做的是对鼠标的每一次动作和得到的命令进行定义。我们称之为监听器。
在画图中,我们需要用到的则是:
java.awt.event.ActionListener;
java.awt.event.MouseListener;
java.awt.event.MouseMotionListener;
这三个接口都是我们所需要用到的。
值得一提的是他们是接口,而并不是类,他们最本质的区别是接口的方法必须被全部的实现,而类中的方法,我们是可以有选择性的去调用的。
首先是:
java.awt.event.ActionListener;
我们使用他来监听我们鼠标动作得到的命令。
代码如下:
public void actionPerformed(ActionEvent e) {
// 得到事件源对象
Object ob = e.getSource();
if (ob instanceof JButton) {
JButton but = (JButton) ob;
// 得到被选中按钮的背景颜色,作为要绘制的颜色
color = but.getBackground();
}
}
然后是:
java.awt.event.MouseListener;
我们在这里所需要用到的主要是我们对鼠标的点击和释放的监听。
代码如下:
public void mousePressed(MouseEvent e) {
// 获取传过来的动作命令
type = group.getSelection().getActionCommand();
// 得到第一次按下时的坐标
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e) {
// 取得鼠标松开时的坐标值
x2 = e.getX();
y2 = e.getY();
g.setColor(color);
// 判断选择的图形
if (type.equals("draw10")) {
// 画直线
g.drawLine(x1, y1, x2, y2);
} else if (type.equals("draw12")) {
// 画矩形
g.drawRect(Math.min(x1, x2), Math.min(y1,y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
} else if (type.equals("draw14")) {
// 画圆
g.drawOval(Math.min(x1,x2),Math.min(y1,y2) , Math.abs(x1 - x2), Math.abs(y1 - y2));
}
}
可以看到的是,在这之中,出现了类似于g.drawRect()的字样。
这些都是我们画图所需要的类java.awt.Graphics之中的。
最后是
java.awt.event.MouseMotionListener;
对他,我们主要用到的是对我们鼠标拖动时的监听。
代码如下:
public void mouseDragged(MouseEvent e) {
// 获取点的坐标值
x2 = e.getX();
y2 = e.getY();
g.setColor(color);
if (type.equals("draw6")) {
// 画曲线
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
} else if (type.equals("draw2")) {// 判断是否是橡皮
g.setColor(Color.WHITE);// 设置颜色为白色
((Graphics2D) g).setStroke(new BasicStroke(10));// 设置线条的大小
g.drawLine(x1, y1, x2, y2);
((Graphics2D) g).setStroke(new BasicStroke(1));// 重新设置线条的大小(还原为1)
x1 = x2;
y1 = y2;
} else if (type.equals("draw7")) {// 判断是否是刷子
((Graphics2D) g).setStroke(new BasicStroke(10));// 设置线条的大小
g.drawLine(x1, y1, x2, y2);
((Graphics2D) g).setStroke(new BasicStroke(1));// 重新设置线条的大小(还原为1)
x1 = x2;
y1 = y2;
} else if (type.equals("draw8")) {// 判断是否是喷枪
// 创建一个随机数对象
Random rand = new Random();
// 循环画10个点
for (int i = 0; i < 10; i++) {
// 随机X
int xValue = rand.nextInt(8);
// 随机Y
int yValue = rand.nextInt(8);
g.drawLine(x2 + xValue, y2 + yValue, x2 + xValue, y2 + yValue);
}
}
}
然后,在我们完成了这些监听器之后,我们将这些监听器加在他们需要放的位置上之后,我们的画图板就可以正常的画画了。
代码如下:
Toolpanel tp = new Toolpanel();
this.add(tp, BorderLayout.WEST);
ColorTool cp = new ColorTool();
this.add(cp, BorderLayout.SOUTH);
// 给画图板添加另一个底色
JPanel center = new JPanel();
center.setLayout(new FlowLayout(0));
center.setBackground(Color.GRAY);
this.add(center, BorderLayout.CENTER);
// 用来绘图的画板
panel = new MyPanel();
panel.setBackground(Color.WHITE);
panel.setPreferredSize(new Dimension(DRAW_WIDTH, DRAW_HEIGHT));
center.add(panel);
this.setVisible(true);
Listener l = new Listener(g, group);
this.addMouseListener(l);
// 在tp中添加鼠标监听器
panel.addMouseListener(l);
panel.addMouseMotionListener(l);
// 给所有颜色按钮添加监听器
cp.addListener(l);
但是,当我们很开心的完成了这些之后,我们会突然的发现,当我们最小化,甚至只是拖动窗体之后,窗体上的画的图形就没有了。很简单,这是因为我们画的东西并没有保存到内存中去,所以,我们还需要对我们的画图板进行进一步的完善,也就是对它们进行重绘。在重绘中,我们需要用到的就是JAVA中的paint()方法。
代码如下:
Public void paint(Graphics g){
super.paint(g);
}
这是最基本的重绘的方法。
但是,对于我们的画图板,我们就有两种重绘的方法。
我进行简单的说明。
第一种:
我们可以获得我们画的每一个线的命令和坐标来进行重绘,这时候,我们需要用到的是一个保存了命令和坐标的数组,简单的代码如下(没有保存的命令,而只是画直线的数组)。
代码如下:
public void paint(Graphics g){
super.paint(g);
int []array=st.getArray();//获取Array中的值
//重新画矩形
for(int i=0;4*i<array.length;i++){
g.drawRect(array[4*i],array[4*i+1],array[4*i+2],array[4*i+3]);
}
}
其中,array数组中保存的就是我们之前存储进去的画直线所需要的坐标。
第二种:
这种方法相对来第一种要显得简单很多,也更加的巧妙。
他是只将一个面板的所有图像记录下来,再进行重绘。
代码如下:
public void drawShape(Graphics g) {
// 得到Panel的背景色
Color backcolor = panel.getBackground();
int back = backcolor.getRGB();
// 遍历二位数组,取出每个像素点的颜色
for (int i = 0; i < Listener.data.length; i++) {
for (int j = 0; j < Listener.data[i].length; j++) {
int num = Listener.data[i][j];
if (back != num) {
// 创建颜色对象
Color color = new Color(num);
g.setColor(color);
g.drawLine(j, i, j, i);
}
}
}
}
class MyPanel extends JPanel {
public MyPanel(){
this.setBackground(Color.white);
}
/**
* 重写父类绘制窗体的方法
*/
public void paint(Graphics g) {
// 调用父类的方法来正确的绘制窗体
super.paint(g);
if (Listener.isPaint) {
// 调用绘制形状的方法
drawShape(g);
}
}
}
最后,在我们能够重绘之后,我们更需要做的事情就是将文件保存在硬盘或者是从硬盘上读出了。这样我们就需要用到的是JAVA中
java.io.DataInputStream;
java.io.DataOutputStream;
java.io.FileInputStream;
java.io.FileOutputStream;
这四个类,其中,这几个类分别是用来从内存中输入输出流,还有将他们打包成能够读写不同类型数据的流。
值得一提的是,在计算机中,我们会定义很多中不同的类型,像int整型,String字符型等等之类的,而普通的流就只能够读写byte字节型,而且最终存储的也一定是byte字节型,但是我们在读取和存入的时候却又不得不考虑我们的所画东西并不是一个Byte字节型,这样,就需要了以Data为开头的对普通流进行打包,使他们能够读取其他类型的类了。
具体代码如下:
public static void saveFile(String path) {
try {
// 创建文件输出流对象
FileOutputStream fos = new FileOutputStream(path);
// 包装成可写基本类型的流
DataOutputStream dos = new DataOutputStream(fos);
// 写图片的高度和宽度
dos.writeInt(Listener.data.length);
dos.writeInt(Listener.data[0].length);
// 遍历二维数组,写数据
for (int i = 0; i < Listener.data.length; i++) {
for (int j = 0; j < Listener.data[i].length; j++) {
int num = Listener.data[i][j];
// 写数据
dos.writeInt(num);
}
}
dos.flush();
fos.close();
} catch (Exception ef) {
ef.printStackTrace();
}
}
/**
* 读取文件中的数据
*
* @param path
* 要读取的文件
* @return 将读取到的数据作为二位数组返回
*/
public static int[][] readFile(String path) {
// 创建文件输入流
try {
FileInputStream fis = new FileInputStream(path);
DataInputStream dis = new DataInputStream(fis);
// 读取高度和宽度
int height = dis.readInt();
int width = dis.readInt();
// 定义二位数组
int[][] readData = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// 将数据读入数组
readData[i][j] = dis.readInt();
}
}
fis.close();
return readData;
} catch (Exception ef) {
ef.printStackTrace();
}
return null;
}
但是,在最后我需要强调的一点就是,虽然我们能够将这些内容保存在硬盘之中,但是不同的文件都有不同的解码器,换句话说,就是如果我们用别的解码器去打开他,这是不能被读取的,产生的就是一堆令人头疼的乱码了,而当我们再用我们的画图板去读取的时候,他却能够正常的读取了。
以上,就是我此次对画图板制作的一些总结。
可能有很多的地方都很不到位,而且有很多的功能都没有得到完善,所以希望大家多多留下自己的指教,轻喷,因为我是一个初学者,有意见我一定是会去改正的。
----------关于画图板
花了将近一个学期的时间,我的画图板也终于是在小部分上已经完工了,至少,他看上去已经是一个画图板了,虽然还有很多功能需要我去完善。
在制作这个画图板的时候,我当然是毫无疑问的遇到了许许多多的问题,而这个总结也是从另一方面对这些问题进行一些阐述吧!也可以算是一个大纲吧!!
首先,想要制作一个画图板,最基本的窗体是少不了的了,这个就是javax.swing.JFrame的顶级容器。
代码如下:
javax.swing.JFrame jf = new javax.swing.JFrame;
然后就是一系列对窗体功能的添加和设定:
他的标题
this.setTitle("画图板");
他的大小
this.setSize(FRAME_WIDTH, FRAME_HEIGHT);
关闭时执行的操作
this.setDefaultCloseOperation(3);
位置
this.setLocationRelativeTo(null);
等等这些能够添加的很多,但是现在只用这些就能让他形成最初的界面,之后的美化可以再继续的进行,甚至可以为他的边框进行自己的设置等等。
当然,在这之中,曾经最让我头疼的就是他的布局了。
但是最重要的是必须要将这个窗口设置为可见,什么都能少就是这个不能少。
代码如下:
This.setVisible(true);
然后,我觉得排在之后的就要是给他加上一个菜单栏了,而实现菜单栏的话,就需要用到一个数组。
在对数组的理解中,数组可以分为多维数组,这里可以是一维的,代码如下;
Object [][]Array=new Object[i][j];
这个定义方法之中需要给数组添加上一定的大小,而i,j就是他们的长度和宽度。
当然还有别的方法,而像我们在菜单栏中所需要用到的数组就是用另外一个方法来获得的,
代码如下:
String [][]Array1={“”};在这里,我们可以添加任意数量的字符串,有多少就加多少,但是一定要用双引号将他们括起来;
String [][]Array2={{“”}{“”}};在这里,很容易发现我使用了三个大括号,没错,这就代表的是这个数组是一个二维数组的定义,当然,大括号的数量并不是说是局限于三个,只是内部的大括号代表多维数组内部的字符串。
在这里我可以用表格来说明一下二维数组的图形来想象一下多维数组的概念。在二维数组中,或者是在数组中,有下标这样一个概念,顾名思义,下标的意思就是标记每一个数组每一个数字,或者字符串,又或者是其他的位置。但是,需要的注意的是,下标是从0开始的。下面我将用i和j来说明一下这个下标。
0 1 2 3 j
1
2
3
4
5
i
如表格中所见,一个数组下标的表示方法Array[i][j];
这里是使用数组的方法。
这样,使用一个数组就可以很轻松的将所需要的命令加入到菜单栏中去了。
在我们使用菜单栏的时候,我们需要用到一下三个类:
1.javax.swing.JMenuBar;
2.javax.swing.JMenuItem;
3.javax.swing.JMenu;
其中,第一个类是创建一个菜单栏,也就是载体;第二个类是给他们加入命令,第三个类是加入载体中的类似于容器的东西。
一个画图板之所以要叫做一个画图板就是因为他能够画图,这也就是下面的代码的核心了。
首先,为了能够好好的画图,我们需要的是一个类似于我们电脑上画图板左边那一栏的图标还有下面那一栏的颜色选项,这两者都是必不可少的。而这两者就都在一个叫做面板的东西上了。在JAVA中,面板需要使用到的类就是java.swing.JPanel。这是一个作为容器的东西,也就是我们放那些菜单栏的选项的地方,这个类所形成的面板也是放在窗体上的,但是他更利于我们对窗体上的分类摆放。
代码如下:
java.swing.JPanel jp=new java.swing.JPanel();
这样,我们就随时能够在jp的对象,也就是面板上添加我们所需要的东西了。
现在,我们拥有了我们放东西的地点,接下来就是放东西了。
首先,是我们左边的选择画什么图形的工具栏。
而为了方便我们的区分和选择,我们将他重新以一个类的形式进行书写,也就是ToolPanel的一个类(这个类是我们自己定义的,和JAVA程序自带的类没有任何的关系)。
在工具栏中,我们会发现有一个一个小的按钮,这些虽然都是按钮,但是和菜单栏的按钮却是不一样的,他们是JAVA中java.swing.JRadioButton中的,也就是按钮类。我们使用这个类可以给面板(JPanel)上添加上一个一个的按钮,而且可以对他们的大小和位置进行设定,这个不进行详细说明,我们需要的说明的是我们在对这些按钮添加图片的方法。因为,我们刚开始创建一个按钮对象之后,这是一个空的,也就是什么都没有在上面的,我们不知道他表示的是什么意思,事实上他们也没有任何的意义,他们只是一个按钮,而他们的意义需要我们给他们添加上,可以是文字也可以使一个图片。
代码如下:
JRadioButton jb = new JRadioButton();
this.add(jb);
但是,我们很容易发现,如果只是一个一个的按钮的话,我们很难去管理,但是恰恰一个画图板的按钮还并不少,所以,这个时候我们就需要一个java.swing.ButtonGroup的类来替我们对这些按钮进行管理。
代码如下:
ButtonGroup group=new ButtonGroup();
这样的话,我们就需要先把所有的按钮放到一起管理再进行添加了
代码如下:
Group.add(jb)
但是,就算我们这样做了, 我们会发现,我们仍然是很难快速的给我们按钮添加我们想要添加的图片或者是文字,因为一个一个的添加值是一件很麻烦的过程,这样就引入了我们需要进行循环的思想。运用一个循环,让计算机去一直按照这个循环去给按钮赋值,这样就大大缩短了我们写代码的时间,也提高的机器的效率。
代码如下:
for (int i = 0; i < 16; i++) {
// 创建按钮
JRadioButton jb = new JRadioButton();
// 设置按钮的大小
jb.setPreferredSize(new Dimension(30, 30));
// 设置图像的地址
jb.setIcon(this.change("picture/draw" + i + ".jpg"));
// 分别设置鼠标在图像上,按下时,松开时的图像
jb.setRolloverIcon(this.change("picture/draw" + i + "-1.jpg"));
jb.setPressedIcon(this.change("picture/draw" + i + "-2.jpg"));
jb.setSelectedIcon(this.change("picture/draw" + i + "-3.jpg"));
// 设按钮的动作命令
jb.setActionCommand("draw" + i);
其中,jb后中均为JButton中本身写有的方法,三种方法依次为设置鼠标在图像上,按下停留,松开时,我们想要给他加上的图像。
小技巧:为了让我们的for循环结构能够成功的运行,我们需要做的就是对我们的图片进行一些有规律性的命名,这样往往能够大大的节省我们的时间,减少我们的工作量。
在这之中,我们有点需要注意的是,在我们的电脑上,我们的对图片的命名是一样的,所以我们的电脑上存在很多相同的名称,但是由于互联网的存在,我们在登录互联网交换信息的时候,不得不想办法去避免那些相同名字的概念,所以,我们的文件的名字就被重新在互联网上进行了定义,也是URL,文件在互联网上唯一的名称。
代码如下:
public ImageIcon change(String path) {
// 将本地路径转化为网络路径
URL u = Toolpanel.class.getResource(path);
// 实例化一个ImageIcon对象,并创建一个图标对象
ImageIcon im = new ImageIcon(u);
// 返回im的值
return im;
}
完成了ToolPanel之后,就是我们的颜色那一栏了,为了方便,我们也将他写成一个单独的类,也就是ColorPanel这个类,这个类也是我们自己定义的一个类,和JAVA本身所带有的类没有任何的关系。
由于颜色按钮本身和文字和图片名有着一定的差别,虽然我们使用的都是按钮,但是,我们在对按钮添加我们想要赋予的意义的时候,就只是对他们的背景色进行的改变了,而我们想要获得的命令也就是他们的背景色。
本处代码与上面的类似,所以略过。
在我们成功的添加了工具栏和颜色栏之后,我们会发现,不管我们多么努力的去点击那些图案,我们也无法像真正的画图板一样去画一些东西。这就是我们并没有对鼠标的动作进行定义的结果。
所以,我们要做的是对鼠标的每一次动作和得到的命令进行定义。我们称之为监听器。
在画图中,我们需要用到的则是:
java.awt.event.ActionListener;
java.awt.event.MouseListener;
java.awt.event.MouseMotionListener;
这三个接口都是我们所需要用到的。
值得一提的是他们是接口,而并不是类,他们最本质的区别是接口的方法必须被全部的实现,而类中的方法,我们是可以有选择性的去调用的。
首先是:
java.awt.event.ActionListener;
我们使用他来监听我们鼠标动作得到的命令。
代码如下:
public void actionPerformed(ActionEvent e) {
// 得到事件源对象
Object ob = e.getSource();
if (ob instanceof JButton) {
JButton but = (JButton) ob;
// 得到被选中按钮的背景颜色,作为要绘制的颜色
color = but.getBackground();
}
}
然后是:
java.awt.event.MouseListener;
我们在这里所需要用到的主要是我们对鼠标的点击和释放的监听。
代码如下:
public void mousePressed(MouseEvent e) {
// 获取传过来的动作命令
type = group.getSelection().getActionCommand();
// 得到第一次按下时的坐标
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e) {
// 取得鼠标松开时的坐标值
x2 = e.getX();
y2 = e.getY();
g.setColor(color);
// 判断选择的图形
if (type.equals("draw10")) {
// 画直线
g.drawLine(x1, y1, x2, y2);
} else if (type.equals("draw12")) {
// 画矩形
g.drawRect(Math.min(x1, x2), Math.min(y1,y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
} else if (type.equals("draw14")) {
// 画圆
g.drawOval(Math.min(x1,x2),Math.min(y1,y2) , Math.abs(x1 - x2), Math.abs(y1 - y2));
}
}
可以看到的是,在这之中,出现了类似于g.drawRect()的字样。
这些都是我们画图所需要的类java.awt.Graphics之中的。
最后是
java.awt.event.MouseMotionListener;
对他,我们主要用到的是对我们鼠标拖动时的监听。
代码如下:
public void mouseDragged(MouseEvent e) {
// 获取点的坐标值
x2 = e.getX();
y2 = e.getY();
g.setColor(color);
if (type.equals("draw6")) {
// 画曲线
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
} else if (type.equals("draw2")) {// 判断是否是橡皮
g.setColor(Color.WHITE);// 设置颜色为白色
((Graphics2D) g).setStroke(new BasicStroke(10));// 设置线条的大小
g.drawLine(x1, y1, x2, y2);
((Graphics2D) g).setStroke(new BasicStroke(1));// 重新设置线条的大小(还原为1)
x1 = x2;
y1 = y2;
} else if (type.equals("draw7")) {// 判断是否是刷子
((Graphics2D) g).setStroke(new BasicStroke(10));// 设置线条的大小
g.drawLine(x1, y1, x2, y2);
((Graphics2D) g).setStroke(new BasicStroke(1));// 重新设置线条的大小(还原为1)
x1 = x2;
y1 = y2;
} else if (type.equals("draw8")) {// 判断是否是喷枪
// 创建一个随机数对象
Random rand = new Random();
// 循环画10个点
for (int i = 0; i < 10; i++) {
// 随机X
int xValue = rand.nextInt(8);
// 随机Y
int yValue = rand.nextInt(8);
g.drawLine(x2 + xValue, y2 + yValue, x2 + xValue, y2 + yValue);
}
}
}
然后,在我们完成了这些监听器之后,我们将这些监听器加在他们需要放的位置上之后,我们的画图板就可以正常的画画了。
代码如下:
Toolpanel tp = new Toolpanel();
this.add(tp, BorderLayout.WEST);
ColorTool cp = new ColorTool();
this.add(cp, BorderLayout.SOUTH);
// 给画图板添加另一个底色
JPanel center = new JPanel();
center.setLayout(new FlowLayout(0));
center.setBackground(Color.GRAY);
this.add(center, BorderLayout.CENTER);
// 用来绘图的画板
panel = new MyPanel();
panel.setBackground(Color.WHITE);
panel.setPreferredSize(new Dimension(DRAW_WIDTH, DRAW_HEIGHT));
center.add(panel);
this.setVisible(true);
Listener l = new Listener(g, group);
this.addMouseListener(l);
// 在tp中添加鼠标监听器
panel.addMouseListener(l);
panel.addMouseMotionListener(l);
// 给所有颜色按钮添加监听器
cp.addListener(l);
但是,当我们很开心的完成了这些之后,我们会突然的发现,当我们最小化,甚至只是拖动窗体之后,窗体上的画的图形就没有了。很简单,这是因为我们画的东西并没有保存到内存中去,所以,我们还需要对我们的画图板进行进一步的完善,也就是对它们进行重绘。在重绘中,我们需要用到的就是JAVA中的paint()方法。
代码如下:
Public void paint(Graphics g){
super.paint(g);
}
这是最基本的重绘的方法。
但是,对于我们的画图板,我们就有两种重绘的方法。
我进行简单的说明。
第一种:
我们可以获得我们画的每一个线的命令和坐标来进行重绘,这时候,我们需要用到的是一个保存了命令和坐标的数组,简单的代码如下(没有保存的命令,而只是画直线的数组)。
代码如下:
public void paint(Graphics g){
super.paint(g);
int []array=st.getArray();//获取Array中的值
//重新画矩形
for(int i=0;4*i<array.length;i++){
g.drawRect(array[4*i],array[4*i+1],array[4*i+2],array[4*i+3]);
}
}
其中,array数组中保存的就是我们之前存储进去的画直线所需要的坐标。
第二种:
这种方法相对来第一种要显得简单很多,也更加的巧妙。
他是只将一个面板的所有图像记录下来,再进行重绘。
代码如下:
public void drawShape(Graphics g) {
// 得到Panel的背景色
Color backcolor = panel.getBackground();
int back = backcolor.getRGB();
// 遍历二位数组,取出每个像素点的颜色
for (int i = 0; i < Listener.data.length; i++) {
for (int j = 0; j < Listener.data[i].length; j++) {
int num = Listener.data[i][j];
if (back != num) {
// 创建颜色对象
Color color = new Color(num);
g.setColor(color);
g.drawLine(j, i, j, i);
}
}
}
}
class MyPanel extends JPanel {
public MyPanel(){
this.setBackground(Color.white);
}
/**
* 重写父类绘制窗体的方法
*/
public void paint(Graphics g) {
// 调用父类的方法来正确的绘制窗体
super.paint(g);
if (Listener.isPaint) {
// 调用绘制形状的方法
drawShape(g);
}
}
}
最后,在我们能够重绘之后,我们更需要做的事情就是将文件保存在硬盘或者是从硬盘上读出了。这样我们就需要用到的是JAVA中
java.io.DataInputStream;
java.io.DataOutputStream;
java.io.FileInputStream;
java.io.FileOutputStream;
这四个类,其中,这几个类分别是用来从内存中输入输出流,还有将他们打包成能够读写不同类型数据的流。
值得一提的是,在计算机中,我们会定义很多中不同的类型,像int整型,String字符型等等之类的,而普通的流就只能够读写byte字节型,而且最终存储的也一定是byte字节型,但是我们在读取和存入的时候却又不得不考虑我们的所画东西并不是一个Byte字节型,这样,就需要了以Data为开头的对普通流进行打包,使他们能够读取其他类型的类了。
具体代码如下:
public static void saveFile(String path) {
try {
// 创建文件输出流对象
FileOutputStream fos = new FileOutputStream(path);
// 包装成可写基本类型的流
DataOutputStream dos = new DataOutputStream(fos);
// 写图片的高度和宽度
dos.writeInt(Listener.data.length);
dos.writeInt(Listener.data[0].length);
// 遍历二维数组,写数据
for (int i = 0; i < Listener.data.length; i++) {
for (int j = 0; j < Listener.data[i].length; j++) {
int num = Listener.data[i][j];
// 写数据
dos.writeInt(num);
}
}
dos.flush();
fos.close();
} catch (Exception ef) {
ef.printStackTrace();
}
}
/**
* 读取文件中的数据
*
* @param path
* 要读取的文件
* @return 将读取到的数据作为二位数组返回
*/
public static int[][] readFile(String path) {
// 创建文件输入流
try {
FileInputStream fis = new FileInputStream(path);
DataInputStream dis = new DataInputStream(fis);
// 读取高度和宽度
int height = dis.readInt();
int width = dis.readInt();
// 定义二位数组
int[][] readData = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// 将数据读入数组
readData[i][j] = dis.readInt();
}
}
fis.close();
return readData;
} catch (Exception ef) {
ef.printStackTrace();
}
return null;
}
但是,在最后我需要强调的一点就是,虽然我们能够将这些内容保存在硬盘之中,但是不同的文件都有不同的解码器,换句话说,就是如果我们用别的解码器去打开他,这是不能被读取的,产生的就是一堆令人头疼的乱码了,而当我们再用我们的画图板去读取的时候,他却能够正常的读取了。
以上,就是我此次对画图板制作的一些总结。
可能有很多的地方都很不到位,而且有很多的功能都没有得到完善,所以希望大家多多留下自己的指教,轻喷,因为我是一个初学者,有意见我一定是会去改正的。
相关推荐
即在内存中创建一个图像缓冲区,用户的所有画图操作都先在这个缓冲区内完成,最后一次性更新到屏幕上,避免闪烁效果。 7. **回放功能**:如果程序支持撤销/重做或记录绘画过程,那么它可能需要保存每一步的绘图动作...
第一种实现方法是基于View类。创建一个自定义的View子类,重写onDraw()方法。在这个方法里,我们需要获取Canvas对象,然后使用Paint设置线条的颜色、宽度等属性。接着,通过Canvas的drawLine()方法来绘制线条。为了...
在C#中实现一个简单的画图板功能,主要是利用Windows Forms应用程序框架以及GDI+图形库。GDI+(Graphics Device Interface Plus)是.NET Framework中用于图形处理的一个强大的库,能够支持2D图形的绘制、填充、文本...
即在内存中创建一个离屏位图,所有绘画操作都在这个位图上完成,最后一次性将位图复制到屏幕,避免闪烁和不连续的绘制效果。 综上所述,开发一个VC++画图程序涉及GUI设计、图形渲染、颜色选择、用户输入处理、图形...
从这次开始,我会由简单到困难(其实也不会困难到哪里去)讲几个例程,每一个例程...我们这次做一个画板,类似Windows里自带的画板,还记不记得第一次接触电脑用画板时的惊叹?现在想起来其实那个真的非常简陋,不过我
3. **注意事项**:绘制曲线时必须进行两次拖动才能完成,第一次拖动画出直线,第二次拖动使直线弯曲。如果仅进行了一次拖动,则需要在原地再次点击鼠标左键以确认绘制。 ### 三、《画图》工具系列-巧用圆形工具 **...
这可能是指Windows操作系统中的“画图”应用程序,也可能是其他第三方的绘图软件。在这个环境中,用户可以进行基本的绘画、编辑和图像处理操作,如绘制线条、形状,填充颜色,复制、粘贴,以及使用橡皮擦等功能。 ...
标题中的“使用C语言编写的嵌入式画图程序”是指使用C编程语言开发的一款用于嵌入式系统的图形用户界面(GUI)应用。C语言因其高效、灵活性和广泛的硬件支持,常被用作嵌入式系统开发的选择。在这个程序中,开发者...
首先,**打开“画图”软件**是开始绘画的第一步。在Windows系统中,可以通过搜索或在开始菜单中找到“画图”应用并启动它。打开后,你会看到一个默认的白色画布,这是你创作的基础。 **保存工作**是非常重要的习惯...
这份八年级下册第一次联考物理试卷主要涵盖了初中物理的基础知识点,包括力、重力、摩擦力、压强、惯性和力的作用效果等多个主题。以下是试卷中涉及的主要知识点的详细解释: 1. **重力**:重力是地球对物体的引力...
绘制曲线需要按住鼠标左键拖动两次,每次拖动都会使线条弯曲一次。通过改变第三次单击点的位置,可以调整封闭区域的大小和形状。此外,通过在第三点单击时保持鼠标不放并移动,可以实时调整封闭区域的大小和方向。 ...
如果只拖动一次,曲线会消失。记得每次拖动后都要在原地点击鼠标左键一次以保持曲线形状。此外,曲线工具还有创建封闭区域的功能,通过点击三个点可以形成一个封闭图形,图形大小和方向可以通过拖动第三点来调整。 ...
绘图软件作为图形设计、工程制图、建筑设计等行业的重要工具,其二次开发能力允许用户或第三方开发者通过编程接口(API)定制功能、集成系统或创建插件,以满足特定需求。这种灵活性对于提升工作效率、解决专业问题...
72. Windows的写字板和画图程序都可以处理文字和图形。选项A和B过于片面,D选项则错误。 73. 当一个应用程序窗口被最小化后,该应用程序会转入后台执行,但仍然运行。 74. 文件是记录在磁盘上的一组相关信息的集合...
1. 计算机历史:世界上第一台电子数字计算机ENIAC是在1946年诞生的。 2. 计算机类型:数模混合计算机既可处理模拟量也可处理数字量。 3. 计算机逻辑判断能力:主要取决于编制的软件。 4. 计算机早期应用:主要是为了...
“GUIDesignStudio_R047”可能是一个专门用于GUI设计的软件,版本号“R047”表示该软件的第47个修订版,这通常意味着软件经过多次迭代,功能更加完善和稳定。安装文件“Setup.exe”表明这是一个Windows平台的安装...
1. 计算机历史:世界上第一台电子数字计算机ENIAC于1946年诞生。 2. 计算机类型:数模混合计算机既能处理模拟量也能处理数字量。 3. 计算机逻辑判断:计算机的逻辑判断能力源于编制的软件。 4. 计算机最初目的:...
7. **安装程序**:DiagramDesignerSetup122.exe很可能是该画图工具的安装程序,版本号122可能表示这是第122次更新或改进版本,意味着开发者不断优化和增强软件性能。 总的来说,"画图工具OurDev"是一个为教育工作者...
- **曲线绘制规则**:绘制曲线需拖动两次,每次拖动形成曲线的一部分。 - **封闭区域绘制**:通过三点(A、B、C)顺序点击,可以自动形成封闭区域,封闭区域大小和方向可通过第三点位置调整。 4. **屏幕拷贝功能*...
Windows系统自带的画图工具是一款简单实用的图像编辑软件,对于初学者来说是学习绘画和基本图像处理的理想选择。下面将详细介绍如何使用这个工具以及它的各种功能。 首先,启动画图工具非常简单,只需在开始菜单的...