问题描述
- 至少提供自由绘画、直线、椭圆、矩形四种模式
- 可插入文本
- 背景色与前端颜色可选
- 图形绘制可选择填充模式与非填充模式
- 绘画的作品可进行保存与加载
总体框架
主体框架即DrawBoard继承自JFrame,上设:
- 2个JPanel(menu与tool,内含数个JButton);
- 1个DrawPanel(继承自JPanel),即画板主体;
- 1个TextArea,在状态变更时显示相应信息。
效果如图:
上方JPanel为菜单,可进行:
- 打开/保存文件(序列化)
- 选择前端颜色
- 选择是否填充图形
- 设置背景颜色
左方JPanel为工具,可供用户在中央画板进行绘画,可选模式为:
- 自由绘画
- 直线
- 椭圆
- 矩形
可在中央画布单击鼠标右键插入文本(下方TextArea有提醒)
实现思路
共7个类,如下图:
- Dshape与Dstr存储已生成的Shape与String;
- DArray由两个ArrayList组成,还有一个Color记录背景色,类别分别为Dshape与Dstr,相当于存储器,是存储以及获取文件时序列化的对象;
- MA继承自MouseAdapter,是DrawPanel最主要的一个监听器,4种绘画模式都要用到,即在鼠标按下时确定起点,释放时确定终点;
- MMA继承自MouseMotionAdapter,是DrawPanel的另一个监听器,仅自由绘画模式会用到,即在鼠标拖动时记录划过的点作为上一条线段的终点及下一条线段的起点,多条线段做出自由绘画的感觉;
- DrawPanel作为主体,记录当前的前端颜色、填充状态、图形类别,并通过重写paintComponent方法以绘制已记录的和正在绘制的图形;
- MTLis继承自ActionListener,是DrawBoard的监听器,根据触发的按钮进行操作;
- DrawBoard继承自JFrame,起框架作用。
源代码
import java.awt.*;import java.awt.event.*;import java.awt.geom.*;import java.io.*;import java.util.ArrayList;import javax.swing.*;classDshapeimplementsSerializable{privatestaticfinallong serialVersionUID=1L;
Shape s;
Color c;boolean f;//填充状态
String m=newString();//绘画模式privatevoidwriteObject(java.io.ObjectOutputStream out)throws IOException{
out.defaultWriteObject();}privatevoidreadObject(java.io.ObjectInputStream in)throws IOException, ClassNotFoundException{
in.defaultReadObject();}}classDstrimplementsSerializable{privatestaticfinallong serialVersionUID=1L;
String s;
Font f;
Color c;int x,y;//坐标privatevoidwriteObject(java.io.ObjectOutputStream out)throws IOException{
out.defaultWriteObject();}privatevoidreadObject(java.io.ObjectInputStream in)throws IOException, ClassNotFoundException{
in.defaultReadObject();}}classDArrayimplementsSerializable{privatestaticfinallong serialVersionUID=1L;
ArrayList<Dshape> shapelist=newArrayList<Dshape>();
ArrayList<Dstr> strlist=newArrayList<Dstr>();
Color backColor;//背景色privatevoidwriteObject(java.io.ObjectOutputStream out)throws IOException{
out.defaultWriteObject();}privatevoidreadObject(java.io.ObjectInputStream in)throws IOException, ClassNotFoundException{
in.defaultReadObject();}}classMAextendsMouseAdapter{
DrawPanel dp;MA(DrawPanel dp){super();this.dp=dp;}@OverridepublicvoidmousePressed(MouseEvent e){//鼠标按下if(dp.tempshape!=null){
dp.da.shapelist.add(dp.tempshape);}switch(dp.model)//据绘制模式对“当前绘制图形(tempshape)”进行初始化{case"Draw":case"Line":{
dp.tempshape=newDshape();
Line2D l=newLine2D.Double();
l.setLine(e.getX(), e.getY(), e.getX(), e.getY());
dp.tempshape.c=dp.currColor;
dp.tempshape.s=l;
dp.tempshape.f=dp.fill;
dp.tempshape.m="Line";break;}case"Ellipse":{
dp.tempshape=newDshape();
Ellipse2D ep=newEllipse2D.Double();
ep.setFrame(e.getX(), e.getY(),0,0);
dp.tempshape.c=dp.currColor;
dp.tempshape.s=ep;
dp.tempshape.f=dp.fill;
dp.tempshape.m="Ellipse";break;}case"Rectangle":{
dp.tempshape=newDshape();
Rectangle2D ra=newRectangle2D.Double();
ra.setFrame(e.getX(), e.getY(),0,0);
dp.tempshape.c=dp.currColor;
dp.tempshape.s=ra;
dp.tempshape.f=dp.fill;
dp.tempshape.m="Rectangle";break;}}}@OverridepublicvoidmouseReleased(MouseEvent e){//鼠标松开switch(dp.model)//完成tempshape的绘制{case"Draw":case"Line":{
Line2D l=(Line2D)(dp.tempshape.s);
l.setLine(l.getX1(), l.getY1(), e.getX(), e.getY());
dp.repaint();break;}case"Ellipse":{
Ellipse2D ep=(Ellipse2D)(dp.tempshape.s);
ep.setFrame(ep.getX(), ep.getY(), e.getX()-ep.getX(), e.getY()-ep.getY());
dp.repaint();break;}case"Rectangle":{
Rectangle2D ra=(Rectangle2D)(dp.tempshape.s);
ra.setFrame(ra.getX(), ra.getY(), e.getX()-ra.getX(), e.getY()-ra.getY());
dp.repaint();break;}}}@OverridepublicvoidmouseClicked(MouseEvent e){//鼠标点击//插入文本if(e.getButton()==MouseEvent.BUTTON3){
String inputValue= JOptionPane.showInputDialog("Please input text");
Font f=newFont("宋体",20,20);
Dstr ms=newDstr();
ms.s=inputValue;
ms.c=dp.currColor;
ms.f=f;
ms.x=e.getX();
ms.y=e.getY();
dp.da.strlist.add(ms);
dp.repaint();}}}classMMAextendsMouseMotionAdapter{privatestaticfinallong serialVersionUID=1L;
DrawPanel dp;MMA(DrawPanel dp){super();this.dp=dp;}@OverridepublicvoidmouseDragged(MouseEvent e){//鼠标拖动//仅自由绘画模式触发if(dp.model.equals("Draw")){if(dp.tempshape!=null){
Line2D l=(Line2D)(dp.tempshape.s);
l.setLine(l.getX1(), l.getY1(), e.getX(), e.getY());
dp.da.shapelist.add(dp.tempshape);}
dp.tempshape=newDshape();
Line2D l=newLine2D.Double();
l.setLine(e.getX(), e.getY(), e.getX(), e.getY());
dp.tempshape.c=dp.currColor;
dp.tempshape.s=l;
dp.repaint();}}}classDrawPanelextendsJPanel{
DArray da=newDArray();
Dshape tempshape;
Color currColor;boolean fill=false;
String model=newString();DrawPanel(){super();
MA ma=newMA(this);this.addMouseListener(ma);
MMA mma=newMMA(this);this.addMouseMotionListener(mma);//设置监听器}@OverridepublicvoidpaintComponent(Graphics g){super.paintComponent(g);
Graphics2D g2d=(Graphics2D) g;for(Dshape ms:da.shapelist){
g2d.setColor(ms.c);if(ms.f&&!ms.m.equals("Line"))
g2d.fill(ms.s);else
g2d.draw(ms.s);}//绘制已记录的图形for(Dstr ms:da.strlist){
g2d.setColor(ms.c);
g2d.setFont(ms.f);
g2d.drawString(ms.s,ms.x,ms.y);}//插入已记录的文本if(tempshape!=null){
g2d.setColor(tempshape.c);if(tempshape.f&&!tempshape.m.equals("Line"))
g2d.fill(tempshape.s);else
g2d.draw(tempshape.s);}//记录当前绘制的图形(若非null)}}classMTLisimplementsActionListener{
DrawBoard bo;MTLis(DrawBoard bo){super();this.bo=bo;}@OverridepublicvoidactionPerformed(ActionEvent ae){// TODO Auto-generated method stubif(ae.getSource().getClass()==JButton.class){
JButton mid=(JButton)ae.getSource();if(mid.getText().equals("Open")){
JFileChooser jf=newJFileChooser();
jf.showOpenDialog(bo);
String s=jf.getSelectedFile().toString();
File f=newFile(s);try{read(f);}catch(ClassNotFoundException| IOException e){// TODO Auto-generated catch block
e.printStackTrace();}
bo.dpl.repaint();
bo.dpl.setBackground(bo.dpl.da.backColor);
bo.message.append("File open "+s+"\n");}//加载文件并将其绘制出来,同时设置背景色if(mid.getText().equals("Save")){if(bo.dpl.tempshape!=null)
bo.dpl.da.shapelist.add(bo.dpl.tempshape);
JFileChooser jf=newJFileChooser();int n=jf.showSaveDialog(bo);
String s=jf.getSelectedFile().toString();
File f=newFile(s);try{write(f);}catch(IOException e){// TODO Auto-generated catch block
e.printStackTrace();}
bo.message.append("File save "+s+"\n");}//记录当前绘制图形,序列化保存if(mid.getText().equals("Color")){
JColorChooser jc=newJColorChooser();
Color c=jc.showDialog(bo, null, null);
bo.dpl.currColor=c;
bo.message.append("Color set "+c.toString()+"\n");}//更改前端颜色if(mid.getText().equals("Fill")){
bo.dpl.fill=!bo.dpl.fill;
bo.message.append("Fill change "+bo.dpl.fill+"\n");}//更改填充状态if(mid.getText().equals("BackgroundColor")){
JColorChooser jc=newJColorChooser();
Color c=jc.showDialog(bo, null, null);
bo.dpl.setBackground(c);
bo.dpl.da.backColor=c;
bo.message.append("BackgroundColor set "+c.toString()+"\n");}//更改背景色if(mid.getText().equals("Draw")){
bo.dpl.model="Draw";
bo.message.append("Model change "+bo.dpl.model+"\n");}if(mid.getText().equals("Line")){
bo.dpl.model="Line";
bo.message.append("Model change "+bo.dpl.model+"\n");}if(mid.