package drawingpanel; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import javax.swing.*; import java.io.*; import java.util.*; public class MiniDrawPad extends JFrame //主类,扩展了JFrame类,用来生成主界面 { private ObjectInputStream input; private ObjectOutputStream output; //定义输入输出流,用来调用和保存图像文件 private JButton choices[]; //按钮数组,存放以下名称的功能按钮 private String names[]={ "New", "Open", "Save", //这三个是基本操作按钮,包括"新建"、"打开"、"保存" /*接下来是我们的画图板上面有的基本的几个绘图单元按钮*/ "Pencil", //铅笔画,也就是用鼠标拖动着随意绘图 "Line", //绘制直线 "Rect", //绘制空心矩形 "fRect", //绘制以指定颜色填充的实心矩形 "Oval", //绘制空心椭圆 "fOval", //绘制以指定颜色填充的实心椭圆 "Circle", //绘制圆形 "fCircle", //绘制以指定颜色填充的实心圆形 "RoundRect", //绘制空心圆角矩形 "frRect", //绘制以指定颜色填充的实心圆角矩形 "Rubber", //橡皮擦,可用来擦去已经绘制好的图案 "Color", //选择颜色按钮,可用来选择需要的颜色 "Stroke", //选择线条粗细的按钮,输入需要的数值可以实现绘图线条粗细的变化 "Word" //输入文字按钮,可以在绘图板上实现文字输入 }; private String styleNames[]={ " 宋体 " , " 隶书 " , " 华文彩云 " , " 仿宋_GB2312 " , " 华文行楷 " , " 方正舒体 " , " Times New Roman " , " Serif " , " Monospaced " , " SonsSerif " , " Garamond " }; //可供选择的字体项 //当然这里的灵活的结构可以让读者自己随意添加系统支持的字体 private Icon items[]; private String tipText[]={ //这里是鼠标移动到相应按钮上面上停留时给出的提示说明条 //读者可以参照上面的按钮定义对照着理解 "Draw a new picture", "Open a saved picture", "Save current drawing", "Draw at will", "Draw a straight line", "Draw a rectangle", "Fill a ractangle", "Draw an oval", "Fill an oval", "Draw a circle", "Fill a circle", "Draw a round rectangle", "Fill a round rectangle", "Erase at will", "Choose current drawing color", "Set current drawing stroke", "Write down what u want" }; JToolBar buttonPanel ; //定义按钮面板 private JLabel statusBar; //显示鼠标状态的提示条 private DrawPanel drawingArea; //画图区域 private int width=800,height=550; //定义画图区域初始大小 drawings[] itemList=new drawings[5000]; //用来存放基本图形的数组 private int currentChoice=3; //设置默认画图状态为随笔画 int index=0; //当前已经绘制的图形数目 private Color color=Color.black; //当前画笔颜色 int R,G,B; //用来存放当前色彩值 int f1,f2; //用来存放当前字体风格 String style1; //用来存放当前字体 private float stroke=1.0f; //设置画笔粗细,默认值为1.0f JCheckBox bold,italic; //定义字体风格选择框 //bold为粗体,italic为斜体,二者可以同时使用 JComboBox styles; public MiniDrawPad() //构造函数 { super("Drawing Pad"); JMenuBar bar=new JMenuBar(); //定义菜单条 JMenu fileMenu=new JMenu("File"); fileMenu.setMnemonic('F'); //新建文件菜单条 JMenuItem newItem=new JMenuItem("New"); newItem.setMnemonic('N'); newItem.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { newFile(); //如果被触发,则调用新建文件函数段 } } ); fileMenu.add(newItem); //保存文件菜单项 JMenuItem saveItem=new JMenuItem("Save"); saveItem.setMnemonic('S'); saveItem.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { saveFile(); //如果被触发,则调用保存文件函数段 } } ); fileMenu.add(saveItem); //打开文件菜单项 JMenuItem loadItem=new JMenuItem("Load"); loadItem.setMnemonic('L'); loadItem.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { loadFile(); //如果被触发,则调用打开文件函数段 } } ); fileMenu.add(loadItem); fileMenu.addSeparator(); //退出菜单项 JMenuItem exitItem=new JMenuItem("Exit"); exitItem.setMnemonic('X'); exitItem.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { System.exit(0); //如果被触发,则退出画图板程序 } } ); fileMenu.add(exitItem); bar.add(fileMenu); //设置颜色菜单条 JMenu colorMenu=new JMenu("Color"); colorMenu.setMnemonic('C'); //选择颜色菜单项 JMenuItem colorItem=new JMenuItem("Choose Color"); colorItem.setMnemonic('O'); colorItem.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { chooseColor(); //如果被触发,则调用选择颜色函数段 } } ); colorMenu.add(colorItem); bar.add(colorMenu); //设置线条粗细菜单条 JMenu strokeMenu=new JMenu("Stroke"); strokeMenu.setMnemonic('S'); //设置线条粗细菜单项 JMenuItem strokeItem=new JMenuItem("Set Stroke"); strokeItem.setMnemonic('K'); strokeItem.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { setStroke(); } } ); strokeMenu.add(strokeItem); bar.add(strokeMenu); //设置提示菜单条 JMenu helpMenu=new JMenu("Help"); helpMenu.setMnemonic('H'); //设置提示菜单项 JMenuItem aboutItem=new JMenuItem("About this Drawing Pad!"); aboutItem.setMnemonic('A'); aboutItem.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "This is a mini drawing pad!\nCopyright (c) 2002 Tsinghua University ", " 画图板程序说明 ", JOptionPane.INFORMATION_MESSAGE ); } } ); helpMenu.add(aboutItem); bar.add(helpMenu); items=new ImageIcon[names.length]; //创建各种基本图形的按钮 drawingArea=new DrawPanel(); choices=new JButton[names.length]; buttonPanel = new JToolBar( JToolBar.VERTICAL ) ; buttonPanel = new JToolBar( JToolBar.HORIZONTAL) ; ButtonHandler handler=new ButtonHandler(); ButtonHandler1 handler1=new ButtonHandler1(); //导入我们需要的图形图标,这些图标都存放在与源文件相同的目录下面 for(int i=0;i<choices.length;i++) {//items[i]=new ImageIcon( MiniDrawPad.class.getResource(names[i] +".gif")); //如果在jbuilder下运行本程序,则应该用这条语句导入图片 items[i]=new ImageIcon(names[i] + ".gif"); //默认的在jdk或者jcreator下运行,用此语句导入图片 choices[i]=new JButton("",items[i]); choices[i].setToolTipText(tipText[i]); buttonPanel.add(choices[i]); } //将动作侦听器加入按钮里面 for(int i=3;i<choices.length-3;i++) { choices[i].addActionListener(handler); } choices[0].addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { newFile(); } } ); choices[1].addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { loadFile(); } } ); choices[2].addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e) { saveFile(); } } ); choices[choices.length-3].addActionListener(handler1); choices[choices.length-2].addActionListener(handler1); choices[choices.length-1].addActionListener(handler1); //字体风格选择 styles=new JComboBox(styleNames); styles.setMaximumRowCount(8); styles.addItemListener( new ItemListener(){ public void itemStateChanged(ItemEvent e) { style1=styleNames[styles.getSelectedIndex()]; } } ); //字体选择 bold=new JCheckBox("BOLD"); italic=new JCheckBox("ITALIC"); checkBoxHandler cHandler=new checkBoxHandler(); bold.addItemListener(cHandler); italic.addItemListener(cHandler); JPanel wordPanel=new JPanel(); buttonPanel.add(bold); buttonPanel.add(italic); buttonPanel.add(styles); styles.setMinimumSize( new Dimension ( 50, 20 ) ); styles.setMaximumSize(new Dimension ( 100, 20 ) ); Container c=getContentPane(); super.setJMenuBar( bar ); c.add(buttonPanel,BorderLayout.NORTH); c.add(drawingArea,BorderLayout.CENTER); statusBar=new JLabel(); c.add(statusBar,BorderLayout.SOUTH); statusBar.setText(" Welcome To The Little Drawing Pad!!! :)"); createNewItem(); setSize(width,height); show(); } //按钮侦听器ButtonHanler类,内部类,用来侦听基本按钮的操作 public class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent e) { for(int j=3;j<choices.length-3;j++) { if(e.getSource()==choices[j]) {currentChoice=j; createNewItem(); repaint();} } } } //按钮侦听器ButtonHanler1类,用来侦听颜色选择、画笔粗细设置、文字输入按钮的操作 public class ButtonHandler1 implements ActionListener { public void actionPerformed(ActionEvent e) { if(e.getSource()==choices[choices.length-3]) {chooseColor();} if(e.getSource()==choices[choices.length-2]) {setStroke();} if(e.getSource()==choices[choices.length-1]) {JOptionPane.showMessageDialog(null, "Please hit the drawing pad to choose the word input position", "Hint",JOptionPane.INFORMATION_MESSAGE ); currentChoice=14; createNewItem(); repaint(); } } } //鼠标事件mouseA类,继承了MouseAdapter,用来完成鼠标相应事件操作 class mouseA extends MouseAdapter { public void mousePressed(MouseEvent e) {statusBar.setText(" Mouse Pressed @:[" + e.getX() + ", " + e.getY() + "]");//设置状态提示 itemList[index].x1=itemList[index].x2=e.getX(); itemList[index].y1=itemList[index].y2=e.getY(); //如果当前选择的图形是随笔画或者橡皮擦,则进行下面的操作 if(currentChoice==3||currentChoice==13) { itemList[index].x1=itemList[index].x2=e.getX(); itemList[index].y1=itemList[index].y2=e.getY(); index++; createNewItem(); } //如果当前选择的图形式文字输入,则进行下面操作 if(currentChoice==14) { itemList[index].x1=e.getX(); itemList[index].y1=e.getY(); String input; input=JOptionPane.showInputDialog( "Please input the text you want!"); itemList[index].s1=input; itemList[index].x2=f1; itemList[index].y2=f2; itemList[index].s2=style1; index++; currentChoice=14; createNewItem(); drawingArea.repaint(); } } public void mouseReleased(MouseEvent e) {statusBar.setText(" Mouse Released @:[" + e.getX() + ", " + e.getY() + "]"); if(currentChoice==3||currentChoice==13) { itemList[index].x1=e.getX(); itemList[index].y1=e.getY(); } itemList[index].x2=e.getX(); itemList[index].y2=e.getY(); repaint(); index++; createNewItem(); } public void mouseEntered(MouseEvent e) { statusBar.setText(" Mouse Entered @:[" + e.getX() + ", " + e.getY() + "]"); } public void mouseExited(MouseEvent e) { statusBar.setText(" Mouse Exited @:[" + e.getX() + ", " + e.getY() + "]"); } } //鼠标事件mouseB类继承了MouseMotionAdapter,用来完成鼠标拖动和鼠标移动时的相应操作 class mouseB extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) {statusBar.setText(" Mouse Dragged @:[" + e.getX() + ", " + e.getY() + "]"); if(currentChoice==3||currentChoice==13) { itemList[index-1].x1=itemList[index].x2=itemList[index].x1=e.getX(); itemList[index-1].y1=itemList[index].y2=itemList[index].y1=e.getY(); index++; createNewItem(); } else { itemList[index].x2=e.getX(); itemList[index].y2=e.getY(); } repaint(); } public void mouseMoved(MouseEvent e) {statusBar.setText(" Mouse Moved @:[" + e.getX() + ", " + e.getY() + "]");} } //选择字体风格时候用到的事件侦听器类,加入到字体风格的选择框中 private class checkBoxHandler implements ItemListener { public void itemStateChanged(ItemEvent e) { if(e.getSource()==bold) if(e.getStateChange()==ItemEvent.SELECTED) f1=Font.BOLD; else f1=Font.PLAIN; if(e.getSource()==italic) if(e.getStateChange()==ItemEvent.SELECTED) f2=Font.ITALIC; else f2=Font.PLAIN; } } //画图面板类,用来画图 class DrawPanel extends JPanel { public DrawPanel() { setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); setBackground(Color.white); addMouseListener(new mouseA()); addMouseMotionListener(new mouseB()); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d=(Graphics2D)g; //定义画笔 int j=0; while (j<=index) { draw(g2d,itemList[j]); j++; } } void draw(Graphics2D g2d,drawings i) { i.draw(g2d);//将画笔传入到各个子类中,用来完成各自的绘图 } } //新建一个画图基本单元对象的程序段 void createNewItem() { if(currentChoice==14)//进行相应的游标设置 drawingArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); else drawingArea.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); switch (currentChoice) { case 3: itemList[index]=new Pencil(); break; case 4: itemList[index]=new Line(); break; case 5: itemList[index]=new Rect(); break; case 6: itemList[index]=new fillRect(); break; case 7: itemList[index]=new Oval(); break; case 8: itemList[index]=new fillOval(); break; case 9: itemList[index]=new Circle(); break; case 10: itemList[index]=new fillCircle(); break; case 11: itemList[index]=new RoundRect(); break; case 12: itemList[index]=new fillRoundRect(); break; case 13: itemList[index]=new Rubber(); break; case 14: itemList[index]=new Word(); break; } itemList[index].type=currentChoice; itemList[index].R=R; itemList[index].G=G; itemList[index].B=B; itemList[index].stroke=stroke; } //选择当前颜色程序段 public void chooseColor() { color=JColorChooser.showDialog(MiniDrawPad.this, "Choose a color",color); R=color.getRed(); G=color.getGreen(); B=color.getBlue(); itemList[index].R=R; itemList[index].G=G; itemList[index].B=B; } //选择当前线条粗细程序段 public void setStroke() { String input; input=JOptionPane.showInputDialog( "Please input a float stroke value! ( >0 )"); stroke=Float.parseFloat(input); itemList[index].stroke=stroke; } //保存图形文件程序段 public void saveFile() { JFileChooser fileChooser=new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); int result =fileChooser.showSaveDialog(this); if(result==JFileChooser.CANCEL_OPTION) return ; File fileName=fileChooser.getSelectedFile(); fileName.canWrite(); if (fileName==null||fileName.getName().equals("")) JOptionPane.showMessageDialog(fileChooser,"Invalid File Name", "Invalid File Name", JOptionPane.ERROR_MESSAGE); else{ try { fileName.delete(); FileOutputStream fos=new FileOutputStream(fileName); output=new ObjectOutputStream(fos); drawings record; output.writeInt( index ); for(int i=0;i< index ;i++) { drawings p= itemList[ i ] ; output.writeObject(p); output.flush(); //将所有图形信息强制转换成父类线性化存储到文件中 } output.close(); fos.close(); } catch(IOException ioe) { ioe.printStackTrace(); } } } //打开一个图形文件程序段 public void loadFile() { JFileChooser fileChooser=new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); int result =fileChooser.showOpenDialog(this); if(result==JFileChooser.CANCEL_OPTION) return ; File fileName=fileChooser.getSelectedFile(); fileName.canRead(); if (fileName==null||fileName.getName().equals("")) JOptionPane.showMessageDialog(fileChooser,"Invalid File Name", "Invalid File Name", JOptionPane.ERROR_MESSAGE); else { try { FileInputStream fis=new FileInputStream(fileName); input=new ObjectInputStream(fis); drawings inputRecord; int countNumber=0; countNumber=input.readInt(); for(index=0;index< countNumber ;index++) { inputRecord=(drawings)input.readObject(); itemList[ index ] = inputRecord ; } createNewItem(); input.close(); repaint(); } catch(EOFException endofFileException){ JOptionPane.showMessageDialog(this,"no more record in file", "class not found",JOptionPane.ERROR_MESSAGE ); } catch(ClassNotFoundException classNotFoundException){ JOptionPane.showMessageDialog(this,"Unable to Create Object", "end of file",JOptionPane.ERROR_MESSAGE ); } catch (IOException ioException){ JOptionPane.showMessageDialog(this,"error during read from file", "read Error",JOptionPane.ERROR_MESSAGE ); } } } //新建一个文件程序段 public void newFile() { index=0; currentChoice=3; color=Color.black; stroke=1.0f; createNewItem(); repaint();//将有关值设置为初始状态,并且重画 } //主函数段 public static void main(String args[]) {try { UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName()); } catch ( Exception e ) {}//将界面设置为当前windows风格 MiniDrawPad newPad=new MiniDrawPad(); newPad.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e) {System.exit(0);}}); } } //定义画图的基本图形单元 class drawings implements Serializable//父类,基本图形单元,用到串行化接口,保存时所用 { int x1,y1,x2,y2; //定义坐标属性 int R,G,B; //定义色彩属性 float stroke; //定义线条粗细属性 int type; //定义字体属性 String s1; String s2; //定义字体风格属性 void draw(Graphics2D g2d){};//定义绘图函数 } /******************************************************************************* 下面是各种基本图形单元的子类,都继承自父类drawings,请仔细理解继承的概念 ********************************************************************************/ class Line extends drawings //直线类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke, BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL)); g2d.drawLine(x1,y1,x2,y2); } } class Rect extends drawings//矩形类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.drawRect(Math.min(x1,x2),Math.min(y1,y2), Math.abs(x1-x2),Math.abs(y1-y2)); } } class fillRect extends drawings//实心矩形类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.fillRect(Math.min(x1,x2),Math.min(y1,y2), Math.abs(x1-x2),Math.abs(y1-y2)); } } class Oval extends drawings//椭圆类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.drawOval(Math.min(x1,x2),Math.min(y1,y2), Math.abs(x1-x2),Math.abs(y1-y2)); } } class fillOval extends drawings//实心椭圆 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.fillOval(Math.min(x1,x2),Math.min(y1,y2), Math.abs(x1-x2),Math.abs(y1-y2)); } } class Circle extends drawings//圆类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.drawOval(Math.min(x1,x2),Math.min(y1,y2), Math.max(Math.abs(x1-x2),Math.abs(y1-y2)), Math.max(Math.abs(x1-x2),Math.abs(y1-y2)) ); } } class fillCircle extends drawings//实心圆 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.fillOval(Math.min(x1,x2),Math.min(y1,y2), Math.max(Math.abs(x1-x2),Math.abs(y1-y2)), Math.max(Math.abs(x1-x2),Math.abs(y1-y2)) ); } } class RoundRect extends drawings//圆角矩形类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.drawRoundRect(Math.min(x1,x2),Math.min(y1,y2), Math.abs(x1-x2),Math.abs(y1-y2), 50,35); } } class fillRoundRect extends drawings//实心圆角矩形类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke)); g2d.fillRoundRect(Math.min(x1,x2),Math.min(y1,y2), Math.abs(x1-x2),Math.abs(y1-y2), 50,35); } } class Pencil extends drawings//随笔画类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(R,G,B)); g2d.setStroke(new BasicStroke(stroke, BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL)); g2d.drawLine(x1,y1,x2,y2); } } class Rubber extends drawings//橡皮擦类 { void draw(Graphics2D g2d) {g2d.setPaint(new Color(255,255,255)); g2d.setStroke(new BasicStroke(stroke+4, BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL)); g2d.drawLine(x1,y1,x2,y2); } } class Word extends drawings//输入文字类 { void draw(Graphics2D g2d) { g2d.setPaint(new Color(R,G,B)); g2d.setFont(new Font(s2,x2+y2,((int)stroke)*18)); if (s1!= null ) g2d.drawString(s1,x1,y1); } }