画图板总结
在蓝杰的第四天,现在还是试听,因为上学期已经把java给学过了加之也做过一些一两个项目,所以学的比较快一点,花了三天的时间现在已经把画图板给做出来了。在这里,谢谢龙哥,谢谢蓝杰的老师和同学们!!
这个画图板正好适合现在我的水平,可以绘制直线,曲线(电脑自带画图板中的画笔),心形,矩形,圆角矩形,三角形,椭圆,和菱形。其他的图形大概都能实现所以就没写。
还可以改变图形的颜色,是否填充,和线条的粗细。我还做了登陆界面,用来练习界面的跳转:
界面就是这样的效果:
在上面我们看到界面上的字体已经变得好看一点,我对字体进行了处理。
和系统自带的画图板相差很大但是,这个对于我来说做出这个东西已经很不错啦。
但是怎么用代码实现呢?在实现的过程中有遇到了什么样的困难呢,现在请看代码:
这里是登陆界面的代码:
1.
package UI; 2. import java.awt.FlowLayout; 3. import java.awt.Font; 4. 5. import javax.swing.*; 6. 7. import tool.LoginListener; 8. 9. /** 10. * 用于创建一个登陆界面 11. * @author ZDX 12. * 13. */ 14. public class LoginFrom extends JFrame { 15. 16. /** 17. * 初始化界面 18. */ 19. public void initLoginFrom(){ 20. //初始化界面 21. this.setTitle("登陆界面");//标题 22. this.setSize(340, 200);//窗体大小 23. /** 24. * 设置窗体关闭时间 25. * DO_NOTHING_ON_CLOSE 点击关闭时无反应 26. * HIDE_ON_CLOSE 点击时将界面隐藏 27. * DISPOSE_ON_CLOSE 将对象销毁 28. * EXIT_ON_CLOSE 退出程序 EXIT_ON_CLOSE = 3; 29. */ 30. 31. this.setDefaultCloseOperation(HIDE_ON_CLOSE); 32. /** 33. * 设置窗体位置 34. */ 35. this.setLocation(300, 400); 36. //设置字体 37. Font font=new Font("微软雅黑",Font.BOLD,15); 38. Font font1=new Font("微软雅黑",Font.BOLD,13); 39. 40. //设置界面的布局管理器 41. FlowLayout fl = new FlowLayout(FlowLayout.LEFT,5,5); 42. this.setLayout(fl); 43. 44. JPanel p1 = new JPanel(new FlowLayout()); 45. JPanel p2 = new JPanel(new FlowLayout()); 46. 47. JLabel jlName = new JLabel("用户名:"); 48. jlName.setFont(font); 49. p1.add(jlName); 50. 51. JTextField jtName = new JTextField(20); 52. p1.add(jtName); 53. 54. JLabel jlPassword = new JLabel(" 密 码 :"); 55. jlPassword.setFont(font); 56. p2.add(jlPassword); 57. 58. JPasswordField password = new JPasswordField(20); 59. p2.add(password); 60. 61. JButton jblogin = new JButton("登录"); 62. jblogin.setFont(font); 63. LoginListener llistener = new LoginListener(this,jtName,password); 64. jblogin.addActionListener(llistener); 65. this.add(p1); 66. this.add(p2); 67. 68. 69. fl.setAlignment(FlowLayout.CENTER); 70. this.add(jblogin); 71. this.setVisible(true); 72. 73. 74. } 75. public static void main(String[] args) { 76. // TODO 自动生成的方法存根 77. LoginFrom login= new LoginFrom(); 78. login.initLoginFrom(); 79. 80. } 81. 82. }
画图板的界面类
虽然组件不多,但是在界面背后有太多的代码,其中的说明已经有注释请看:
package UI;
83. import java.awt.BorderLayout;
84. import java.awt.Color;
85. import java.awt.Dimension;
86. import java.awt.FlowLayout;
87. import java.awt.Font;
88. import java.awt.Graphics;
89. import java.util.ArrayList;
90.
91. import javax.swing.ButtonGroup;
92. import javax.swing.JButton;
93. import javax.swing.JComboBox;
94. import javax.swing.JFrame;
95. import javax.swing.JLabel;
96. import javax.swing.JPanel;
97. import javax.swing.JRadioButton;
98.
99. import tool.ColorListener;
100. import tool.DrawListener;
101. import tool.LineSizeListener;
102. import tool.PropertyListener;
103. import tool.Shape;
104. import tool.ShapeObject;
105.
106. public class DrawFrom extends JFrame {
107.
108. public static ArrayList<ShapeObject> shapeList = new ArrayList<ShapeObject>();
109.
110. public void initDrawFrom() {
111. this.setTitle("画图板");
112. this.setSize(600, 590);
113. this.setDefaultCloseOperation(3);
114.
115. BorderLayout bl = new BorderLayout();
116. this.setLayout(bl);
117.
118. Font font=new Font("微软雅黑",Font.BOLD,15);
119. Font font1=new Font("微软雅黑",Font.BOLD,13);
120.
121. // 工具面板
122. JPanel jpTool = new JPanel(new FlowLayout(FlowLayout.LEFT));
123. // 工具面板的字面板 颜色面板
124. jpTool.setBackground(Color.blue);
125. //工具面板的大小设置
126. jpTool.setPreferredSize(new Dimension(400, 150));
127. /**
128. * 一下生成颜色选择控件
129. */
130. // 生成颜色标签
131. JLabel jlcolor = new JLabel("颜色选取");
132. jlcolor.setFont(font);
133. //设置面板的大小必须使用setPreferredSize来设置
134. jlcolor.setPreferredSize(new Dimension(60, 60));
135.
136. // 生成颜色面板
137. JPanel jpcolor = new JPanel();
138. jpcolor.setPreferredSize(new Dimension(250, 60));// 颜色面板的大小
139. jpcolor.setBackground(Color.red);
140. jpcolor.setLayout(new FlowLayout(FlowLayout.LEFT));// 颜色面板的布局方式
141.
142. //将颜色组件放在工具面板上
143. jpTool.add(jlcolor);
144. jpTool.add(jpcolor);
145.
146.
147. //填充和线条粗细选择面板
148. JPanel jpFlAndLineSize = new JPanel();
149. //設置顏色
150. jpFlAndLineSize.setBackground(Color.green);
151. jpFlAndLineSize.setPreferredSize(new Dimension(220, 60));
152. //下面是填充组件
153. JLabel jbIsFill = new JLabel(" 是否填充");
154. jbIsFill.setFont(font);
155. jpFlAndLineSize.add(jbIsFill);
156.
157. JRadioButton yesFill = new JRadioButton("是");
158. yesFill.setBackground(Color.YELLOW);
159. yesFill.setFont(font1);
160. jpFlAndLineSize.add(yesFill);
161.
162.
163. JRadioButton noFill = new JRadioButton("否");
164. noFill.setBackground(Color.YELLOW);
165. noFill.setFont(font1);
166. jpFlAndLineSize.add(noFill);
167.
168. //设置一个空间组,逻辑概念使其只能选择一个选项
169. ButtonGroup bgFill = new ButtonGroup();
170. bgFill.add(noFill);
171. bgFill.add(yesFill);
172.
173. //粗细组件
174. JLabel jlLineSize = new JLabel(" 选取线条粗细");
175. //设置字体
176. jlLineSize.setFont(font);
177. //设置下拉列表
178. JComboBox lineSize = new JComboBox();
179. //向列表中添加选项
180. lineSize.setModel(new javax.swing.DefaultComboBoxModel(
181. new String[] { "1", "2", "3" ,"4","5","6","7","8","9","10","11","12","13"}));
182. jpFlAndLineSize.add(jlLineSize);
183. jpFlAndLineSize.add(lineSize);
184.
185. jpTool.add(jpFlAndLineSize);
186.
187.
188.
189.
190.
191.
192. //形状选择组件
193. JLabel jlshape = new JLabel("选择形状");
194. jlshape.setFont(font);
195. jpTool.add(jlshape);
196. // 创建图形选择面板
197. JPanel jpshape = new MyJpanel();
198. // 形状按钮数组
199. JButton[] jbshape = new JButton[8];
200. String[] icon = new String[8];
201. icon[0] = new String("直线");
202. icon[1] = new String("曲线");
203. icon[2] = new String("心形");
204. icon[3] = new String("椭圆");
205. icon[4] = new String("矩形");
206. icon[5] = new String("圆角矩形");
207. icon[6] = new String("三角形");
208. icon[7] = new String("菱形");
209.
210. for (int i = 0; i < 8; i++) {
211. jbshape[i] = new JButton(icon[i]);
212. jbshape[i].setFont(font1);
213. jpshape.add(jbshape[i]);
214. }
215.
216.
217. // //画图面板
218. JPanel jpDraw = new MyJpanel();
219. //设置画板的背景色
220. jpDraw.setBackground(Color.WHITE);
221. //设置画板的大小
222.
223. jpDraw.setPreferredSize(new Dimension(400, 400));
224. this.add(jpTool, BorderLayout.NORTH);
225. this.add(jpDraw, BorderLayout.SOUTH);
226.
227. JButton[] jbcolor = new JButton[13];
228. //将颜色存储在数组中便组件颜色设置
229. Color[] color = new Color[13];
230. color[0] = Color.RED;
231. color[1] = Color.orange;
232. color[2] = Color.YELLOW;
233. color[3] = Color.GREEN;
234. color[4] = Color.BLUE;
235. color[5] = Color.CYAN;
236. color[6] = Color.PINK;
237. color[7] = Color.GRAY;
238. color[8] = Color.WHITE;
239. color[9] = Color.black;
240. color[10] = Color.darkGray;
241. color[11] = Color.magenta;
242. color[12] = Color.lightGray;
243. for (int i = 0; i < 13; i++) {
244. jbcolor[i] = new JButton();
245. //设置组件的颜色
246. jbcolor[i].setBackground(color[i]);
247. //设置组建的大小
248. jbcolor[i].setPreferredSize(new Dimension(20, 20));
249. //将组件添加在面板上
250. jpcolor.add(jbcolor[i]);
251.
252. }
253.
254.
255.
256.
257. jpTool.add(jpshape);
258. //是页面显示出来
259. this.setVisible(true);
260.
261. /**
262. * 创建监听器并为各个组件添加监听器,注意设置监听器一般是在
263. * this.setVisible(true)之后
264.
265. */
266. ColorListener cls = new ColorListener();
267.
268. //获得面板的绘图纸,注意画板的获取必须在this.setVisible(true);
269. // 之后,原因:g的获取是在界面呈现出来之后,才获取到的画板的信息。
270. //如画板的位置等等。。。。
271. Graphics g = jpDraw.getGraphics();
272. //循环为颜色组建设置监听
273. for (int i = 0; i < 13; i++) {
274. jbcolor[i].addActionListener(cls);
275. }
276.
277. //创建一个属性(是否为填充)监听器
278. PropertyListener ppl = new PropertyListener();
279. //为组件添加这个监听器
280. yesFill.addActionListener(ppl);
281. noFill.addActionListener(ppl);
282. //创建一个属性(线条大小)监听器
283. LineSizeListener sizeListener = new LineSizeListener(lineSize);
284. lineSize.addActionListener(sizeListener);
285.
286. Shape shape = Shape.Curve;
287. //为形状按钮添加监听
288. for (int i = 0; i < 8; i++) {
289. jbshape[i].addActionListener(ppl);
290. }
291.
292.
293.
294. DrawListener dl = new DrawListener(jpDraw, g);
295. jpDraw.addMouseListener(dl);
296. jpDraw.addMouseMotionListener(dl);
297.
298. }
299.
300. /**
301. * 此类很重要,继承了面板类,然后对paint进行重写
302. * 把每个图形对象从shapeList链表数组中取出来重新绘制在面板上,解决了图形在面板上犹豫界面重绘造成的,图形丢失
303. * 还把每个图形的最后一次留下的痕迹再画出来,此处是重点,技术难点,解决了画图闪动的问题
304. * @author ZDX
305. *
306. */
307. class MyJpanel extends JPanel {
308. public void paint(Graphics g) {
309. super.paint(g);
310.
311. //在每次界面进行重绘时使得图形保留在界面
312. for (int i = 0; i < shapeList.size(); i++) {
313. ShapeObject drawShape = shapeList.get(i);
314. //把每个图形画在界面上
315. drawShape.draw(g);
316. }
317. //此代码尤为重要,它解决了画图板闪烁的问题
318. if (DrawListener.drawShape != null) {
319. DrawListener.drawShape.draw(g);
320. }
321.
322. }
323. }
324. }
之后的代码主要集中在各种监听器,和一个图形的类,类中提供了画出各种图形的方法。
下面做一一列举:
登录窗口的监听器:
327.
328.
package tool;
329.
330. import java.awt.event.ActionEvent;
331. import java.awt.event.ActionListener;
332.
333. import javax.swing.JPasswordField;
334. import javax.swing.JTextField;
335.
336. import UI.DrawFrom;
337. import UI.LoginFrom;
338.
339. public class LoginListener implements ActionListener {
340.
341. // 用户名文本区
342. JTextField jtName;
343. // 密码文本区
344. JPasswordField password;
345. // 创建一个登录窗口
346. LoginFrom login;
347.
348. public LoginListener(LoginFrom login, JTextField jtName,
349. JPasswordField password) {
350. this.login = login;
351. this.jtName = jtName;
352. this.password = password;
353. }
354.
355. @Override
356. public void actionPerformed(ActionEvent e) {
357. // TODO 自动生成的方法存根
358. // 获得输入的用户名
359. String userName = jtName.getText();
360. // 获得输入的密码
361. String userPassword = password.getText();
362. // 这里为了操作简单起见,将用户名和密码认证设置为空
363. if (userName.equals("") && userPassword.equals("")) {
364. // 创建一个画图界面,即主界面
365. DrawFrom drawform = new DrawFrom();
366. drawform.initDrawFrom();
367. // 将登陆窗口设置为不可见
368. login.setVisible(false);
369.
370. }
371.
372. }
373.
374. }
375.
颜色监听器:
376.
377.
package tool;
378. package tool;
379.
380. import java.awt.Color;
381. import java.awt.event.ActionEvent;
382. import java.awt.event.ActionListener;
383.
384. import javax.swing.JButton;
385. /**
386. * 颜色监听器,用于图形颜色的控制
387. * @author ZDX
388. *
389. */
390. public class ColorListener implements ActionListener{
391.
392. //将颜色改为静态变量,便于其他类中传入数值
393. public static Color color;
394.
395. @Override
396. public void actionPerformed(ActionEvent e) {
397. // TODO 自动生成的方法存根
398. //获取事件触发的对象,并得到其背景颜色
399. JButton obj = (JButton) e.getSource();
400. color = obj.getBackground();
401.
402. }
403.
404. }
405.
下面是画图绘制监听,负责将图像绘制在画图面板jpDraw上,代码如下:
package tool;
408.
409. import java.awt.Graphics;
410. import java.awt.event.MouseAdapter;
411. import java.awt.event.MouseEvent;
412.
413. import javax.swing.JPanel;
414.
415. import UI.DrawFrom;
416.
417. public class DrawListener extends MouseAdapter {
418.
419. private int x1;
420. private int y1;
421. private int x2;
422. private int y2;
423. // 线条的粗壮
424. private int size;
425. // 画图面板
426. private JPanel jpDraw;
427. // 画布
428. Graphics g;
429. // 图形的形状
430. private Shape shape;
431. // 创建一个图形对象
432. public static ShapeObject drawShape;
433.
434. public DrawListener(JPanel jpDraw, Graphics g) {
435. this.jpDraw = jpDraw;
436. this.g = g;
437.
438. }
439.
440. @Override
441. public void mouseClicked(MouseEvent e) {
442. // TODO 自动生成的方法存根
443.
444. }
445.
446. @Override
447. public void mousePressed(MouseEvent e) {
448. // TODO 自动生成的方法存根
449. // 从线条型号监听器获得图形粗细
450. size = LineSizeListener.size;
451. // 从属性监听器获得图形的形状
452. shape = PropertyListener.shape;
453. // 得到鼠标所在位置
454. x1 = e.getX();
455. y1 = e.getY();
456.
457. }
458.
459. /**
460. * 拖动时用于显示图形的动态显示
461. */
462. public void mouseDragged(MouseEvent e) {
463.
464. //拖动时,获取每一点的位置
465. x2 = e.getX();
466. y2 = e.getY();
467. //每次拖动时,创建每一个图形对象
468. drawShape = new ShapeObject(x1, y1, x2, y2, shape, size);
469.
470. /**
471. * 画曲线的时候比较特殊,因为要时时改变起始位置和结束位置
472. * 其他的形状则用公共的方法来绘制
473. */
474. if (shape == Shape.Curve) {
475. x1 = x2;
476. y1 = y2;
477. DrawFrom.shapeList.add(drawShape);
478. }
479. //使用repaint方法,在进行拖动时擦除因为拖动所留下的轨迹
480. jpDraw.repaint();
481. drawShape.draw(g);
482. }
483.
484. @Override
485. public void mouseReleased(MouseEvent e) {
486. // TODO 自动生成的方法存根
487. x2 = e.getX();
488. y2 = e.getY();
489.
490. /**
491. * 将图形对象加入到动态数组中,用来重绘图案
492. */
493. DrawFrom.shapeList.add(drawShape);
494. }
495.
496. }
下面是控制线条大小的监听器,LineSizeListener,功能简单,不作详细介绍。代码如下:
499.
500. package tool;
501.
502. import java.awt.event.ActionEvent;
503. import java.awt.event.ActionListener;
504.
505. import javax.swing.JComboBox;
506.
507. public class LineSizeListener implements ActionListener {
508. private JComboBox lineSize;
509.
510. public static int size;
511. public LineSizeListener(JComboBox lineSize) {
512.
513. this.lineSize = lineSize;
514. }
515.
516.
517. @Override
518. public void actionPerformed(ActionEvent e) {
519. // TODO 自动生成的方法存根
520. //获取用户所选的项,并将其转化为字符串
521. if(lineSize.getSelectedItem().toString()!=null){
522. //将所选的项转化为整形你
523. size = Integer.parseInt(lineSize.getSelectedItem().toString());
524. }else{
525. size = 3;
526. }
527.
528. }
529.
530. }
531.
532.
一下这个类及其强大的。其实这个类可以完全代替画图板工具栏中以上所有组件监听器的功能,但是在第一次开发的时候因为技术水平有限。没能够做到完美,请读者引以为戒。
代码如下:
package tool;
534.
535. import java.awt.Color;
536. import java.awt.event.ActionEvent;
537. import java.awt.event.ActionListener;
538.
539. import javax.swing.JButton;
540. import javax.swing.JComboBox;
541.
542. /**
543. * 此类用来控制图形对象的颜色,形状,是否填充三个属性
544. *
545. * @author ZDX
546. *
547. */
548. public class PropertyListener implements ActionListener {
549.
550. // 声明三个静态属性,便于值得传递
551. public static Color color;
552. public static Shape shape;
553. public static boolean isFill;
554.
555. public PropertyListener() {
556.
557. }
558.
559. public void actionPerformed(ActionEvent e) {
560.
561. // TODO 自动生成的方法存根
562. // 此方法很重要,它可以追踪鼠标点击的组件。我们可以根据追踪到的组件信息来设置相应的图行属性。这个方法的作用可以是该类代替工具栏其他组件的监听器
563. String strShape = e.getActionCommand();
564.
565. switch (strShape) {
566. case "是":
567. isFill = true;
568. break;
569. case "否":
570. isFill = false;
571. break;
572. case "直线":
573. shape = Shape.Line;
574. break;
575. case "曲线":
576. shape = Shape.Curve;
577. break;
578. case "心形":
579. shape = Shape.Heart;
580. break;
581. case "椭圆":
582. shape = Shape.Oval;
583. break;
584. case "矩形":
585. shape = Shape.Rect;
586. break;
587. case "菱形":
588. shape = Shape.Diamond;
589. break;
590. case "圆角矩形":
591. shape = Shape.RoundRect;
592. break;
593. case "三角形":
594. shape = Shape.Triangle;
595. break;
596. // default:
597. // System.out.println("snvdineivnieniovno");
598. //
599. }
600. }
601.
602. }
以下是一个枚举,枚举出了图形的各种形状。代码:
603. package tool;
604.
605. public enum Shape {
606.
607. Line,//直线
608. Curve,//曲线
609. Oval,//椭圆
610. Rect,//矩形
611. Triangle,//三角形
612. RoundRect,//圆角矩形
613. Diamond , //菱形
614. Heart //心形
615. }
其他的类只剩下一个ShapeObject类和一个NetJavaShap类。在这里就不做一一的举例。作为一个初学者,各位大神看到我的代码后,估计或忍不住吐槽:这么劣质的代码也敢拿出来晾???
嗯哪,就是这个样子吧,这个画图板开发的过程中我遇到的不少的问题,在解决的过程中得到龙哥的悉心指点。这个画图板也正是我走向强大的第一步,做这个玩意,使我学到了很多东西。简单快捷高效,快速了解了在课堂上,在学校里面自己摸索要花费很多时间的技术与知识。技术探索之路任重而道远,我只是才跨出了第一步。