ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Java学习进程6

Java学习进程6 图形重绘及类与对象继简易画图工具功能实现后见Java学习进程3需解决隐藏窗体后图形消失的问题。为什么能看到窗体Java中所有的swing组件都有一个paint方法能够绘制组件本身。组件重绘组件重绘当改变窗体状态隐藏改变大小都会导致 窗体上所有的组件重新调用paint方法。面向对象编程把绘制出来的图形看作一个对象在代码设计对应的类示例代码对应example中的Shape类,保存该图形的数据继承绘制图形的组件类(JPanel),重写该组件的paint方法示例代码对应example中的JPanel类继承 JPanel 重写 paint 方法实现全局重绘在该方法增加绘制图形的功能example实现所有的图形重绘(颜色粗细)注多边形存储思路看成多个线段对象DrawListener类packagecom.yw.oop0619;importjava.awt.*;importjava.awt.event.*;importjava.util.Random;/** * author YAN * date 2026/5/26 16:43 * description */publicclassDrawListenerimplementsMouseListener,ActionListener,MouseMotionListener{//引用传递publicGraphicsgr;//保存传递过来的画笔对象//全部变量属性publicintx1,y1,x2,y2,x3,y3,x4,y4;publicStringname;//设置标记位控制代码执行顺序publicintflag1;publicColorcolorColor.BLACK;//定义Shape类型的数组publicShape[]shapeArrnewShape[5000];publicintindex0;//设置默认粗细publicfloatstrokeSize1.0f;//动作监听器处理方法publicvoidactionPerformed(ActionEvente){Stringstre.getActionCommand();if(蓝色.equals(str)){colorColor.BLUE;}elseif(红色.equals(str)){colorColor.RED;}elseif(绿色.equals(str)){colorColor.GREEN;}elseif(粗.equals(str)){strokeSize3.0f;// 粗}elseif(细.equals(str)){strokeSize1.0f;// 细}else{namestr;}gr.setColor(color);setStroke(strokeSize);}publicvoidsetStroke(floatsize){Graphics2Dg2(Graphics2D)gr;g2.setStroke(newBasicStroke(size));}//鼠标监听器处理方法publicvoidmouseClicked(MouseEvente){x3e.getX();y3e.getY();if(三角形.equals(name)){setStroke(strokeSize);gr.drawLine(x1,y1,x3,y3);gr.drawLine(x2,y2,x3,y3);ShapeshapenewShape(name,x1,y1,x2,y2,x3,y3,color,strokeSize);shapeArr[index]shape;flag1;System.out.println(x3 x3 y3 y3);}if(多边形.equals(name)){setStroke(strokeSize);//gr.drawLine(x2, y2, x3, y3);//让当前线段的终点变成下条线段的起点//x2 x3;//y2 y3;//判断是否双击 e.getClickCount() 2//绘制最后一条线段if(e.getClickCount()2){gr.drawLine(x2,y2,x1,y1);ShapecloseLinenewShape(多边形,x2,y2,x1,y1,color,strokeSize);shapeArr[index]closeLine;flag1;}else{gr.drawLine(x2,y2,x3,y3);ShapelinenewShape(多边形,x2,y2,x3,y3,color,strokeSize);shapeArr[index]line;x2x3;y2y3;}}}publicvoidmousePressed(MouseEvente){System.out.println(按下);//获取当前坐标值//作用域一对大括号就是一个独立作用域//局部变量1.在方法(作用域)中定义的变量 2.方法的参数if(flag1){x1e.getX();y1e.getY();if(曲线.equals(name)){x4x1;y4y1;}}System.out.println(x1 x1 y1 y1);}publicvoidmouseReleased(MouseEvente){System.out.println(松开);if(flag1){x2e.getX();y2e.getY();}System.out.println(x2 x2 y2 y2);//绝对值intwMath.abs(x2-x1);inthMath.abs(y2-y1);//取最小值intmxMath.min(x1,x2);//设置粗细setStroke(strokeSize);if(直线.equals(name)){//存入当前颜色、粗细ShapeshapenewShape(name,x1,y1,x2,y2,color,strokeSize);shapeArr[index]shape;}if(矩形.equals(name)){//矩形gr.drawRect(mx,y1,w,h);ShapeshapenewShape(name,x1,y1,x2,y2,color,strokeSize);shapeArr[index]shape;}//任意三角形if(三角形.equals(name)||(多边形.equals(name)flag1)){gr.drawLine(x1,y1,x2,y2);flag;}}//绘制迭代分形publicvoiddraw(){//随机取点RandomrannewRandom();intaxran.nextInt(600);intayran.nextInt(600);intbxran.nextInt(600);intbyran.nextInt(600);intcxran.nextInt(600);intcyran.nextInt(600);intpx0;intpy0;for(inti0;i10000;i){//随机选择A B Cintnumran.nextInt(3);if(num0){//Apx(axpx)/2;py(aypy)/2;}elseif(num1){//Bpx(bxpx)/2;py(bypy)/2;}elseif(num2){//Cpx(cxpx)/2;py(cypy)/2;}gr.drawLine(px,py,px,py);}}publicvoidmouseDragged(MouseEvente){if(直线.equals(name)){//绘制图形setStroke(strokeSize);gr.setColor(Color.WHITE);gr.drawLine(x1,y1,x4,y4);x4e.getX();y4e.getY();gr.setColor(color);gr.drawLine(x1,y1,x4,y4);}//曲线每一段短线存入数组if(曲线.equals(name)){intcurXe.getX();intcurYe.getY();setStroke(strokeSize);gr.setColor(color);gr.drawLine(x4,y4,curX,curY);ShapecurveSegnewShape(曲线,x4,y4,curX,curY,color,strokeSize);shapeArr[index]curveSeg;x4curX;y4curY;}x4e.getX();y4e.getY();if(橡皮擦.equals(name)){interaseX1x1;interaseY1y1;interaseX2e.getX();interaseY2e.getY();//复制画笔Graphics2Dg2(Graphics2D)gr.create();// 给橡皮擦单独设置粗线条g2.setStroke(newBasicStroke(8));g2.setColor(Color.WHITE);g2.drawLine(x1,y1,x4,y4);// 用完后释放不影响原画笔g2.dispose();ShapeeraseShapenewShape(橡皮擦,eraseX1,eraseY1,eraseX2,eraseY2,Color.WHITE,8.0f);shapeArr[index]eraseShape;//更新起点为当前鼠标位置实现连续擦除x1eraseX2;y1eraseY2;}}publicvoidmouseMoved(MouseEvente){}publicvoidmouseEntered(MouseEvente){}publicvoidmouseExited(MouseEvente){}}DrawUI类packagecom.yw.oop0619;importjavax.swing.*;importjava.awt.*;/** * author YAN * date 2026/5/26 16:43 * description */publicclassDrawUI{//显示画图工具的界面publicvoidshowUI(){JFramejfnewJFrame();jf.setSize(800,800);jf.setTitle(画图工具);jf.setLocationRelativeTo(null);jf.setDefaultCloseOperation(3);//边框布局BorderLayoutbordernewBorderLayout();jf.setLayout(border);//功能面板JPanelnorthPanelnewJPanel();northPanel.setBackground(Color.GREEN);northPanel.setPreferredSize(newDimension(0,40));jf.add(northPanel,BorderLayout.NORTH);DrawListenerlistenernewDrawListener();//定义字符串数组保存按钮上的内容String[]name{直线,矩形,三角形,多边形,曲线,橡皮擦,粗,细,红色,蓝色,绿色};//遍历数组for(inti0;iname.length;i){JButtonjbunewJButton(name[i]);northPanel.add(jbu);jbu.addActionListener(listener);}//画图面板MPaneldrawPanelnewMPanel();drawPanel.setBackground(Color.WHITE);jf.add(drawPanel,BorderLayout.CENTER);jf.setVisible(true);//画笔图形内容显示在哪个组件上画笔就从该组件上获取//从面板上获取画笔对象一定要在窗体显示可见之后GraphicsgdrawPanel.getGraphics();//监听器//1.事件源当前动作所发生的组件(swing)窗体//2.监听器鼠标监听器方法:addMouseListener()//3.绑定事件处理类//给窗体添加鼠标监听器方法drawPanel.addMouseListener(listener);//鼠标拖动监听器方法drawPanel.addMouseMotionListener(listener);//传递画笔对象glistener.grg;//新增默认初始化值listener.setStroke(listener.strokeSize);//从DrawListener类中传递数据到MPanel类中drawPanel.shapeArrlistener.shapeArr;}publicstaticvoidmain(String[]args){DrawUIuinewDrawUI();ui.showUI();}}MPanel类packagecom.yw.oop0619;importjavax.swing.*;importjava.awt.*;/** * author YAN * date 2026/6/19 20:44 * description */publicclassMPanelextendsJPanel{publicShape[]shapeArr;publicvoidpaint(Graphicsg){super.paint(g);if(shapeArrnull)return;for(inti0;ishapeArr.length;i){ShapeshapeshapeArr[i];if(shapenull)break;shape.drawShape(g);}}}Shape类packagecom.yw.oop0619;importjava.awt.*;/** * author YAN * date 2026/6/19 20:28 * description */publicclassShape{//属性publicintx1,y1,x2,y2,x3,y3;publicStringname;publicColorcolorColor.BLACK;//保存线条粗细publicfloatstrokeSize1.0f;//直线、多边形、矩形、曲线publicShape(Stringname,intx1,inty1,intx2,inty2,Colorcolor,floatstrokeSize){this.namename;this.x1x1;this.y1y1;this.x2x2;this.y2y2;this.colorcolor;this.strokeSizestrokeSize;}//三角形publicShape(Stringname,intx1,inty1,intx2,inty2,intx3,inty3,Colorcolor,floatstrokeSize){this.namename;this.x1x1;this.y1y1;this.x2x2;this.y2y2;this.x3x3;this.y3y3;this.colorcolor;this.strokeSizestrokeSize;}publicvoiddrawShape(Graphicsg){Graphics2Dg2(Graphics2D)g;//重绘时使用图形自己保存的颜色、粗细g2.setColor(this.color);g2.setStroke(newBasicStroke(this.strokeSize));switch(name){case直线:case多边形:case曲线:case橡皮擦:g.drawLine(x1,y1,x2,y2);break;case矩形:intwMath.abs(x2-x1);inthMath.abs(y2-y1);intminXMath.min(x1,x2);intminYMath.min(y1,y2);g.drawRect(minX,minY,w,h);break;case三角形:g.drawLine(x1,y1,x2,y2);g.drawLine(x2,y2,x3,y3);g.drawLine(x3,y3,x1,y1);break;}}}关于类和对象构造函数改进储存数据方法在创建对象时赋值构造方法构造方法书写格式public方法名参数类型 参数名{方法体}作用1创建对象参考创建对象格式类名 对象名new构造方法作用2带参数的构造方法通过构造方法传进参数给某对象属性赋值。特点可同时给多个属性赋值区别1.构造方法没有返回值类型 2.方法名必须是类名注意每个类都有一个默认的无参构造方法当自己定义构造方法那么默认的无参构造方法就会被替代构造方法 set方法已知想要调用私用属性可以定义一个公共的set方法获取该属性则用get方法。那么什么情况下使用set什么时候调用构造方法呢使用set方法的情况在创建对象后需要修改数据而大多数情况下使用构造方法更方便创建对象同时赋值无法修改该值。构造方法的相互调用this注意必须写在第一句作用设置对象的默认值this关键字表示当前类的对象方法重载在同一个类中同一个方法通过参数选择实现不同的功能要求1.方法名重名 2.参数类型个数顺序不同
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进