问题描述
- 至少提供自由绘画、直线、椭圆、矩形四种模式
- 可插入文本
- 背景色与前端颜色可选
- 图形绘制可选择填充模式与非填充模式
- 绘画的作品可进行保存与加载
总体框架
主体框架即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.*;
class Dshape implements Serializable{
private static final long serialVersionUID = 1L;
Shape s;
Color c;
boolean f;//填充状态
String m=new String();//绘画模式
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
out.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
{
in.defaultReadObject();
}
}
class Dstr implements Serializable{
private static final long serialVersionUID = 1L;
String s;
Font f;
Color c;
int x,y;//坐标
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
out.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
{
in.defaultReadObject();
}
}
class DArray implements Serializable{
private static final long serialVersionUID = 1L;
ArrayList<Dshape> shapelist=new ArrayList<Dshape>();
ArrayList<Dstr> strlist=new ArrayList<Dstr>();
Color backColor;//背景色
private void writeObject(java.io.ObjectOutputStream out) throws IOException
{
out.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
{
in.defaultReadObject();
}
}
class MA extends MouseAdapter{
DrawPanel dp;
MA(DrawPanel dp)
{
super();
this.dp=dp;
}
@Override
public void mousePressed(MouseEvent e){//鼠标按下
if(dp.tempshape!=null) {
dp.da.shapelist.add(dp.tempshape);
}
switch(dp.model)
//据绘制模式对“当前绘制图形(tempshape)”进行初始化
{
case "Draw":
case "Line":
{
dp.tempshape=new Dshape();
Line2D l=new Line2D.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=new Dshape();
Ellipse2D ep=new Ellipse2D.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=new Dshape();
Rectangle2D ra=new Rectangle2D.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;
}
}
}
@Override
public void mouseReleased(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;
}
}
}
@Override
public void mouseClicked(MouseEvent e){//鼠标点击
//插入文本
if(e.getButton()==MouseEvent.BUTTON3)
{
String inputValue = JOptionPane.showInputDialog("Please input text");
Font f=new Font("宋体",20,20);
Dstr ms=new Dstr();
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();
}
}
}
class MMA extends MouseMotionAdapter{
private static final long serialVersionUID = 1L;
DrawPanel dp;
MMA(DrawPanel dp)
{
super();
this.dp=dp;
}
@Override
public void mouseDragged(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=new Dshape();
Line2D l=new Line2D.Double();
l.setLine(e.getX(), e.getY(), e.getX(), e.getY());
dp.tempshape.c=dp.currColor;
dp.tempshape.s=l;
dp.repaint();
}
}
}
class DrawPanel extends JPanel{
DArray da= new DArray();
Dshape tempshape;
Color currColor;
boolean fill=false;
String model=new String();
DrawPanel()
{
super();
MA ma=new MA(this);
this.addMouseListener(ma);
MMA mma=new MMA(this);
this.addMouseMotionListener(mma);
//设置监听器
}
@Override
public void paintComponent(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)
}
}
class MTLis implements ActionListener{
DrawBoard bo;
MTLis(DrawBoard bo)
{
super();
this.bo=bo;
}
@Override
public void actionPerformed(ActionEvent ae) {
// TODO Auto-generated method stub
if(ae.getSource().getClass()==JButton.class)
{
JButton mid=(JButton)ae.getSource();
if(mid.getText().equals("Open"))
{
JFileChooser jf=new JFileChooser();
jf.showOpenDialog(bo);
String s=jf.getSelectedFile().toString();
File f=new File(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=new JFileChooser();
int n=jf.showSaveDialog(bo);
String s=jf.getSelectedFile().toString();
File f=new File(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=new JColorChooser();
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=new JColorChooser();
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.getText().equals("Ellipse"))
{
bo.dpl.model="Ellipse";
bo.message.append("Model change "+bo.dpl.model+"\n");
}
if(mid.getText().equals("Rectangle"))
{
bo.dpl.model="Rectangle";
bo.message.append("Model change "+bo.dpl.model+"\n");
}//更改绘画模式
}
}
void write(File f) throws IOException
{
FileOutputStream fo=new FileOutputStream(f);
@SuppressWarnings("resource")
ObjectOutputStream oo=new ObjectOutputStream(fo);
oo.writeObject(bo.dpl.da);
}//序列化写
void read(File f) throws IOException, ClassNotFoundException
{
FileInputStream fi=new FileInputStream(f);
@SuppressWarnings("resource")
ObjectInputStream oi=new ObjectInputStream(fi);
DArray dp=(DArray)oi.readObject();
bo.dpl.da=dp;
}//序列化读
}
public class DrawBoard extends JFrame{
JPanel menu;
JButton open,save,color,fill,bgc;
JPanel tool;
JButton draw,line,el,rect;
DrawPanel dpl;
JTextArea message;
JScrollPane frame;
DrawBoard(String title)
{
super();
this.setTitle(title);
menu=new JPanel(new GridLayout(1,5));
open=new JButton("Open");
save=new JButton("Save");
color=new JButton("Color");
fill=new JButton("Fill");
bgc=new JButton("BackgroundColor");
menu.add(open);
menu.add(save);
menu.add(color);
menu.add(fill);
menu.add(bgc);
tool=new JPanel(new GridLayout(4,1));
draw=new JButton("Draw");
line=new JButton("Line");
el=new JButton("Ellipse");
rect=new JButton("Rectangle");
tool.add(draw);
tool.add(line);
tool.add(el);
tool.add(rect);
dpl=new DrawPanel();
String m="Please click right mouse button where you wanna to input text\n";
message=new JTextArea(m,3,5);
frame = new JScrollPane(message);
this.getContentPane().add("North",menu);
this.getContentPane().add("West",tool);
this.getContentPane().add("Center",dpl);
this.getContentPane().add("South",frame);
addli();
this.setSize(800,500);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
void addli()
{
MTLis m =new MTLis(this);
open.addActionListener(m);
save.addActionListener(m);
color.addActionListener(m);
fill.addActionListener(m);
bgc.addActionListener(m);
draw.addActionListener(m);
line.addActionListener(m);
el.addActionListener(m);
rect.addActionListener(m);
}//加入监听器
public static void main(String[]arg)
{
DrawBoard d=new DrawBoard("Test");
}
}