前言
继上篇笔记,当时鼠标监听器绑定在JFrame窗体上,会出现绘图坐标错位,同时任意三角形交互逻辑不完善。本次修复坐标偏移问题,完善自定义三角形绘制逻辑,使用flag状态变量控制多步绘图流程。
一、实现思路
这个画图工具的核心就是窗体 + 事件监听器。
我们分成两大块来写:
- DrawUI3 :负责搭建窗口、创建顶部按钮面板、白色绘图画布;鼠标监听器绑定绘图面板,解决坐标错位,把监听器绑定到按钮上。
- DrawListener3 :实现 ActionListener 和 MouseListener ,接收按钮点击事件、鼠标按下/松开/单击事件,拿到画布画笔去绘图,使用flag标记记录绘图阶段。
整体流程:
点击图形/颜色按钮 → 记录当前选中的功能,重置绘图状态 → 在白色画布上操作鼠标 → 监听器捕获画布鼠标坐标 → 一步式图形直接绘图;自定义三角形先拖拽底边,flag切换状态,单击画布获取第三个顶点完成闭合。
二、实现步骤
步骤1:搭建主窗体
我们先创建 JFrame 窗口,设置大小、标题、关闭方式;
使用BorderLayout布局,上方放置JPanel存放功能按钮,中间JPanel作为白色绘图画布;
创建各个功能按钮:直线、矩形、等腰三角形、三角形、蓝色、红色、黑色;
步骤2:编写监听器
监听器需要实现两个接口:
1、ActionListener :监听按钮点击,记住现在要画什么图形 / 什么颜色,切换按钮重置flag状态。
2、MouseListener :监听鼠标按下、松开、单击,获取坐标完成绘图。
需要定义的变量:
1、Graphics gr :画笔
2、x1,y1 :鼠标按下起点; x2,y2 :鼠标松开终点; x3,y3 :三角形第三个点
3、String name :保存当前选中的功能名称
4、boolean flag:绘图状态标记,true可以拖拽绘制底边,false等待单击获取三角形顶点
然后重写五个鼠标方法 + 按钮响应方法:
1、actionPerformed() :按钮被点击,更新 name、设置画笔颜色;重置flag绘图状态
2、mousePressed() :鼠标按下,flag为true时记录起点 x1,y1
3、mouseReleased() :鼠标松开,拿到终点 x2,y2;执行直线、矩形、等腰三角形;三角形模式绘制底边,将flag置为false等待单击
4、mouseClicked():鼠标单击,flag为false时获取三角形第三个点,连线闭合三角形,重置flag
5、mouseEntered / mouseExited :接口必须实现,这里暂时留空
三、代码案例
packagesy0922;importjavax.swing.*;importjava.awt.*;importjava.net.http.WebSocket;publicclassDrawUI3{publicvoidinitUI(){JFramejf=newJFrame();jf.setTitle("画图工具");jf.setSize(800,800);jf.setLocationRelativeTo(null);jf.setDefaultCloseOperation(3);JPanelnorthPanel=newJPanel();northPanel.setBackground(Color.PINK);northPanel.setPreferredSize(newDimension(0,40));jf.add(northPanel,BorderLayout.NORTH);JButtonjbu=newJButton("直线");northPanel.add(jbu);JButtonjbu2=newJButton("矩形");northPanel.add(jbu2);JButtonjbu3=newJButton("等腰三角形");northPanel.add(jbu3);JButtonjbu4=newJButton("三角形");northPanel.add(jbu4);JButtonjbu5=newJButton("多边形");northPanel.add(jbu5);JButtonblue=newJButton("蓝色");northPanel.add(blue);JButtonred=newJButton("红色");northPanel.add(red);JButtonblack=newJButton("黑色");northPanel.add(black);JPaneldrawPanel=newJPanel();jf.add(drawPanel,BorderLayout.CENTER);jf.setVisible(true);Graphicsg=drawPanel.getGraphics();DrawListener3listener=newDrawListener3();listener.gr=g;drawPanel.addMouseListener(listener);jbu.addActionListener(listener);jbu2.addActionListener(listener);jbu3.addActionListener(listener);jbu4.addActionListener(listener);jbu5.addActionListener(listener);blue.addActionListener(listener);red.addActionListener(listener);black.addActionListener(listener);listener.gr=g;}publicstaticvoidmain(String[]args){DrawUI3ui=newDrawUI3();ui.initUI();}}packagesy0922;importjava.awt.*;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.awt.event.MouseEvent;importjava.awt.event.MouseListener;publicclassDrawListener3implementsMouseListener,ActionListener{publicGraphicsgr;publicintx1,y1,x2,y2,x3,y3;publicStringname;publicbooleanflag=true;publicvoidactionPerformed(ActionEvente){name=e.getActionCommand();if("蓝色".equals(name)){gr.setColor(Color.blue);}if("红色".equals(name)){gr.setColor(Color.red);}if("黑色".equals(name)){gr.setColor(Color.black);}}publicvoidmouseClicked(MouseEvente){x3=e.getX();y3=e.getY();if("三角形".equals(name)){gr.drawLine(x1,y1,x3,y3);gr.drawLine(x2,y2,x3,y3);flag=true;}}publicvoidmousePressed(MouseEvente){if(flag==true){x1=e.getX();y1=e.getY();}}publicvoidmouseReleased(MouseEvente){if(flag==true){x2=e.getX();y2=e.getY();}intw=Math.abs(x1-x2);intmx=Math.min(x1,x2);if("直线".equals(name)){gr.drawLine(x1,y1,x2,y2);}if("矩形".equals(name)){gr.drawRect(mx,y1,w,y2-y1);}if("等腰三角形".equals(name)){gr.drawLine(x1,y2,(x1+x2)/2,y1);gr.drawLine((x1+x2)/2,y1,x2,y2);gr.drawLine(x1,y2,x2,y2);}if("三角形".equals(name)){gr.drawLine(x1,y1,x2,y2);flag=false;}}publicvoidmouseEntered(MouseEvente){}publicvoidmouseExited(MouseEvente){}}运行结果
五、学习小结
画图工具的实现本身不难,难的是状态管理。像直线这种“一步完成”的图形很好写,但像任意三角形这种需要两次鼠标动作的图形,就必须使用flag变量记住程序当前处于哪一个阶段。同时理解不同组件的鼠标坐标原点差异,监听器绑定不同组件,拿到的鼠标坐标结果完全不一样。后续还可以继续拓展,实现清空画布、多边形绘制等功能。