畫圖軟件
一、需求
利用面向對象的思想,設計並實現一個畫圖軟件。實現基本的圖形繪製功能、文本繪製功能、橡皮檫功能、撤銷功能以及圖片的存取功能,畫圖軟件具有美觀的用戶界面。使用戶可以繪製直線、曲線、矩形、圓、三角形、五邊形、六邊形和橢圓等基本圖形,可以設置畫筆的粗細和顏色,以及繪製填充圖形,文件讀取最終實現jpg、bmp、png和gif格式的存取。
二、總體設計
通過分析,畫圖軟件主界面主要分爲菜單欄、工具欄、調色板、畫板和狀態欄五個部分,將主界面設計爲一個MyFrame類,將主界面上的菜單欄、工具欄、調色板等均分裝成一個類,完成各自的功能。將菜單欄分裝成MyMenu類,主要實現圖片的打開、保存和新建功能,畫筆顏色粗細設置功能,以及軟件的使用說明;將工具欄封裝成MyToolbar類,主要實現圖形繪製按鈕,文本繪製、文本字體大小和字體風格的設置,同時添加保存文件、清空畫板和撤銷功能的快捷按鈕;將調色板封裝成ColorPanel類,主要用來設置畫筆的顏色,可以使用設計好的16種顏色,也可以通過JColorChooser(顏色選擇器)選擇更多的顏色;將畫板封裝成DrawPanel類,主要實現圖形以及文本的繪製;狀態欄作爲MyFrame類的成員變量,用於顯示鼠標當前的位置。
對於圖形繪製,設計一個抽象Shape類,包含圖形繪製的基本屬性值和一個抽象draw(Graphics2D g)方法;其他圖形類對象均繼承Shape類,並實現抽象方法。
程序一共設計com.edu.nwafu.shape、com.edu.nwafu.start和com.edu.nwafu.tool三個包,分別存放圖形類對象、主界面和調色板。
三、最終軟件效果圖
四、代碼
MyFrame類
package com.edu.nwafu.start;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import com.edu.nwafu.shape.Circle;
import com.edu.nwafu.shape.Hexagon;
import com.edu.nwafu.shape.Images;
import com.edu.nwafu.shape.Line;
import com.edu.nwafu.shape.Oval;
import com.edu.nwafu.shape.Brush;
import com.edu.nwafu.shape.Pencil;
import com.edu.nwafu.shape.Pentagon;
import com.edu.nwafu.shape.Rectangle;
import com.edu.nwafu.shape.RoundRect;
import com.edu.nwafu.shape.Rubber;
import com.edu.nwafu.shape.Shape;
import com.edu.nwafu.shape.Text;
import com.edu.nwafu.shape.Triangle;
import com.edu.nwafu.shape.FillCircle;
import com.edu.nwafu.shape.FillOval;
import com.edu.nwafu.shape.FillRect;
import com.edu.nwafu.shape.FillRoundRect;
import com.edu.nwafu.tool.ColorPanel;
public class MyFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
// 保存文件的標誌
public static int saved = 0;
// private Container c;
// 聲明顏色屬性,並賦默認值
public static Color c = Color.black;
// String oldName; // 原窗口名標記
// 按鈕屬性,便於其他類訪問
public Graphics2D g;// 畫筆
public int lengthCount; // 鉛筆或橡皮擦圖形的存儲長度
// private JButton[] btn_paint;// 定義各種繪圖的按鈕
public static String fontName = new String(" 宋體 ");
private static int fSize = 16;
private static int blodtype = Font.PLAIN;// 粗體,默認正常
private static int italic = Font.PLAIN;// 斜體
// private ImageIcon[] icon; // 存放按鈕的圖片
public static int index = 0;// 圖形形狀的標記
public static Shape[] itemList = new Shape[5000];// 圖形存儲單元
private DrawPanel drawingArea; // 畫圖區域
private JLabel statusBar;// 鼠標狀態
public static int stroke = 1;// 畫筆粗細
public static Color color = Color.black;// 用於存放當前顏色
public static int currentChoice = 3; // 初始狀態是畫筆
// 菜單類
MyMenu menu;
// 工具條
MyToolbar myToolbar;
// 調色板
ColorPanel colorPanel;
int length; // 鉛筆或橡皮擦的筆跡長度
public MyFrame(String s) {
init(s);
setVisible(true);
}
public MyFrame() {
}
public void init(String s) {
this.setTitle(s);// 設置標題
this.setSize(950, 600);// 設置窗口大小
this.setLocationRelativeTo(null);// 居中顯示
// 添加菜單
menu = new MyMenu();
myToolbar = new MyToolbar();
colorPanel = new ColorPanel();
add(colorPanel, BorderLayout.WEST);
// 設置窗體圖標
try {
ImageIcon imageIcon = new ImageIcon(getClass().getResource("/image/themeicon.png"));
Image image = imageIcon.getImage();
this.setIconImage(image);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "圖標異常");
}
// 創建各種基本圖形的按鈕
drawingArea = new DrawPanel();
this.add(drawingArea, BorderLayout.CENTER);
statusBar = new JLabel();
this.add(statusBar, BorderLayout.SOUTH);
statusBar.setText("座標");
/**
* 由於JLable是透明的,當我們把JLabel控件加載到JPanel控件之上時, 會發現JLabel的背景色總是和JPanel的背景色保持一致,
*/
statusBar.setOpaque(true);// 設置該組件爲透明
statusBar.setBackground(new Color(195, 195, 195));
drawingArea.createNewGraphics();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
if (saved == 0) {
int n = JOptionPane.showConfirmDialog(null, "您還沒保存,確定要退出?", "提示", JOptionPane.OK_CANCEL_OPTION);
if (n == 0) {
System.exit(0);
}
}
if (saved == 1) {
System.exit(0);
}
}
});
}
// 畫圖面板類,用來畫圖
class DrawPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawPanel() {
// 設置光標類型,爲十字形
this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
//設置背景顏色
this.setBackground(Color.white);
//設置鼠標監聽
this.addMouseListener(new mouseAction());
this.addMouseMotionListener(new MouseMOtion());
}
//重寫paintComponent方法,使得畫板每次刷新時可將之前的所有圖形重新畫出來。
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, Shape shape) {
shape.draw(g2d); // 將畫筆傳入到各個子類中,用來完成各自的繪圖
}
// 撤銷操作的實現
public void undo() {
index--;
if (index >= 0) {
if (currentChoice == 3 || currentChoice == 16 || currentChoice == 17) {
index -= itemList[index].length;
} else {
index--;
}
drawingArea.repaint();
}
index++;
drawingArea.createNewGraphics();
}
// 新建一個畫圖基本單元對象的程序段
public void createNewGraphics() {
/**
* MOVE_CURSOR:移動光標類型。 CROSSHAIR_CURSOR:十字光標 CUSTOM_CURSOR 制定類型 WAIT_CURSOR
* 等待光標類型
*/
if (currentChoice == 16) {
try {
// 定義鼠標進入畫板時的樣式
String url = "/image/cursor.png"; // 儲存鼠標圖片的位置
Toolkit tk = Toolkit.getDefaultToolkit();
Image image = new ImageIcon(getClass().getResource(url)).getImage();
Cursor cursor = tk.createCustomCursor(image, new Point(10, 10), "norm");
drawingArea.setCursor(cursor);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "自定義光標異常");
}
} else if (currentChoice == 18) {
drawingArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
} else {
drawingArea.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));// 光標設置
}
switch (currentChoice) {
case 0:
itemList[index] = new Images();
break;
case 3:
itemList[index] = new Pencil();
break;
case 4:
itemList[index] = new Line();
break;
case 5:
itemList[index] = new Rectangle();
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 Triangle();
break;
case 14:
itemList[index] = new Pentagon();
break;
case 15:
itemList[index] = new Hexagon();
break;
case 16:
itemList[index] = new Rubber();
break;
case 17:
itemList[index] = new Brush();
break;
case 18:
itemList[index] = new Text();
String input;
input = JOptionPane.showInputDialog("請輸入文字");
itemList[index].s = input;
itemList[index].fontSize = fSize;
itemList[index].fontName = fontName;
itemList[index].italic = italic;
itemList[index].blodtype = blodtype;
break;
}
itemList[index].color = color;
itemList[index].width = stroke;
}
// 鼠標事件mouseAction類,繼承了MouseAdapter,用來完成鼠標相應事件操作
class mouseAction extends MouseAdapter {
public void mousePressed(MouseEvent e) {
statusBar.setText("座標:[" + e.getX() + "," + e.getY() + "]像素");// 設置狀態提示
itemList[index].x1 = itemList[index].x2 = e.getX();
itemList[index].y1 = itemList[index].y2 = e.getY();
// 如果當前選擇的圖形是畫筆或者橡皮檫,則進行下面的操作
if (currentChoice == 3 || currentChoice == 16 || currentChoice == 17) {
lengthCount = 0;
itemList[index].x1 = itemList[index].x2 = e.getX();
itemList[index].y1 = itemList[index].y2 = e.getY();
index++;
lengthCount++;
createNewGraphics();
}
}
public void mouseReleased(MouseEvent e) {
statusBar.setText("座標:[" + e.getX() + "," + e.getY() + "]像素");
if (currentChoice == 3 || currentChoice == 16 || currentChoice == 17) {
itemList[index].x1 = e.getX();
itemList[index].y1 = e.getY();
lengthCount++;
itemList[index].length = lengthCount;
}
itemList[index].x2 = e.getX();
itemList[index].y2 = e.getY();
repaint();
index++;
createNewGraphics();
}
public void mouseEntered(MouseEvent e) {
statusBar.setText("座標:[" + e.getX() + "," + e.getY() + "]像素");
}
public void mouseExited(MouseEvent e) {
statusBar.setText("座標:");
}
}
// 鼠標事件mouseMOtion類繼承了MouseMotionAdapter,用來完成鼠標拖動和鼠標移動時的響應操作
class MouseMOtion extends MouseMotionAdapter {
public void mouseDragged(MouseEvent e) {
statusBar.setText("座標:[" + e.getX() + "," + e.getY() + "]像素");
if (currentChoice == 3 || currentChoice == 16 || currentChoice == 17) {
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++;
lengthCount++;
createNewGraphics();
} else {
itemList[index].x2 = e.getX();
itemList[index].y2 = e.getY();
}
repaint();
}
public void mouseMoved(MouseEvent e) {
statusBar.setText("座標:[" + e.getX() + "," + e.getY() + "]像素");
}
}
}
// 保存圖形文件程序
class MyMenu {
/**
* 菜單初始化部分
*/
private JMenuBar jMenuBar;// 菜單條
private JMenuItem file_item_new, file_item_open, file_item_save, file_item_exit;// 定文件菜單的菜單項
private JMenuItem set_item_color, set_item_undo;// 定設置菜單的菜單項
private JMenuItem[] stroke_item;
private JMenuItem help_item_info;
private JMenuItem help_item_use;
private JMenu file_menu, set_menu, help_menu, stroke_menu;// 定義文件、設置、幫助菜單
private String strokes[] = { "/image/stroke1.png", "/image/stroke2.png", "/image/stroke3.png",
"/image/stroke4.png" };
public MyMenu() {
addMenu();
}
public void addMenu() {
jMenuBar = new JMenuBar();
stroke_item = new JMenuItem[strokes.length];
// 實例化菜單對象
file_menu = new JMenu("文件");
set_menu = new JMenu("設置");
help_menu = new JMenu("幫助");
stroke_menu = new JMenu("粗細");
// 實例化菜單項,並通過ImageIcon對象添加圖片
file_item_new = new JMenuItem("新建", new ImageIcon(getClass().getResource("/image/new.png")));
file_item_open = new JMenuItem("打開", new ImageIcon(getClass().getResource("/image/open.png")));
file_item_save = new JMenuItem("保存", new ImageIcon(getClass().getResource("/image/save.png")));
file_item_exit = new JMenuItem("退出", new ImageIcon(getClass().getResource("/image/exit.png")));
set_item_color = new JMenuItem("顏色", new ImageIcon(getClass().getResource("/image/color.png")));
set_item_undo = new JMenuItem("撤銷", new ImageIcon(getClass().getResource("/image/undo.png")));
help_item_use = new JMenuItem("使用手冊");
help_item_info = new JMenuItem("關於畫圖");
for (int i = 0; i < 4; i++) {
stroke_item[i] = new JMenuItem("", new ImageIcon(getClass().getResource(strokes[i])));
stroke_menu.add(stroke_item[i]);
}
help_item_info.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,
"" + "關於畫圖\n" + "****該軟件由沈仕瑞開發完成****\n" + "****班級:計算機1602班 *****\n"
+ "****學號:2016012841 *****\n" + "****郵箱:[email protected]\n",
"關於畫圖", JOptionPane.PLAIN_MESSAGE);
}
});
help_item_use.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "" + "##################\r\n" + "#畫圖軟件使用說明書#\r\n"
+ "####################\r\n" + "1.本軟件可以實現以下功能:\r\n" + "(1)在畫布上繪製直線、矩形、橢圓等圖形\r\n"
+ "(2)設置畫筆的顏色和粗細\r\n" + "(3)繪製填充圖形\r\n" + "(4)依據鼠標軌跡繪製曲線\r\n" + "(5)橡皮擦、保存圖片\r\n"
+ "2.本軟件主要分爲四個模塊:菜單、工具欄、調色板、和畫布\r\n" + "(1)菜單欄的文件子菜單包括打開、新建、保存圖片以及退出程序,設置有快捷鍵,方便操作,\r\n"
+ " 菜單欄的設置子菜單包括設置畫筆的粗細和顏色;\r\n" + "(2)工具欄主要包括保存文件、清空畫板、撤回操作、圖形繪製和文字的繪製;\r\n"
+ "(3)調色板位於界面的左側,用於設置畫筆的顏色,可以使用已設定的顏色,也可以自己選擇系統提供的顏色;\r\n"
+ "(4)畫布用於圖形繪製,使用鼠標選中要繪製的圖形即可進行繪製。", "使用說明", JOptionPane.PLAIN_MESSAGE);
}
});
help_menu.add(help_item_use);
help_menu.add(help_item_info);
// 設置快捷鍵
file_item_new.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
file_item_open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
file_item_save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
file_item_exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
set_item_undo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK));
// 添加粗細子菜單
// 添加菜單項到菜單
file_menu.add(file_item_new);
file_menu.add(file_item_open);
file_menu.add(file_item_save);
file_menu.add(file_item_exit);
set_menu.add(set_item_color);
set_menu.add(set_item_undo);
set_menu.add(stroke_menu);
// 添加菜單到菜單條
jMenuBar.add(file_menu);
jMenuBar.add(set_menu);
jMenuBar.add(help_menu);
// 添加菜單條
setJMenuBar(jMenuBar);
// 給文件菜單設置監聽
file_item_new.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
menu.newFile();
}
});
file_item_save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 保存文件,並將標誌符saved設置爲1
menu.saveFile();
saved = 1;
}
});
file_item_open.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 打開文件,並將標誌符saved設置爲0
menu.openFile();
saved = 0;
}
});
file_item_exit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 如果文件已經保存就直接退出,若果文件沒有保存,提示用戶選擇是否退出
if (saved == 1) {
System.exit(0);
} else {
int n = JOptionPane.showConfirmDialog(null, "您還沒保存,確定要退出?", "提示", JOptionPane.OK_CANCEL_OPTION);
if (n == 0) {
System.exit(0);
}
}
}
});
// 給設置菜單添加監聽
set_item_color.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 設置粗細
ColorPanel.chooseColor();
}
});
set_item_undo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 撤銷
drawingArea.undo();
}
});
stroke_item[0].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stroke = 1;
itemList[index].width = stroke;
}
});
stroke_item[1].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stroke = 5;
itemList[index].width = stroke;
}
});
stroke_item[2].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stroke = 15;
itemList[index].width = stroke;
}
});
stroke_item[3].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stroke = 25;
itemList[index].width = stroke;
}
});
}
// 保存圖形文件
public void saveFile() {
// 文件選擇器
JFileChooser fileChooser = new JFileChooser();
// 設置文件顯示類型爲僅顯示文件
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
// 文件過濾器
JpgFilter jpg = new JpgFilter();
BmpFilter bmp = new BmpFilter();
PngFilter png = new PngFilter();
GifFilter gif = new GifFilter();
// 向用戶可選擇的文件過濾器列表添加一個過濾器。
fileChooser.addChoosableFileFilter(jpg);
fileChooser.addChoosableFileFilter(bmp);
fileChooser.addChoosableFileFilter(png);
fileChooser.addChoosableFileFilter(gif);
// 返回當前的文本過濾器,並設置成當前的選擇
fileChooser.setFileFilter(fileChooser.getFileFilter());
// 彈出一個 "Save File" 文件選擇器對話框
int result = fileChooser.showSaveDialog(MyFrame.this);
if (result == JFileChooser.CANCEL_OPTION) {
return;
}
File fileName = fileChooser.getSelectedFile();
if (!fileName.getName().endsWith(fileChooser.getFileFilter().getDescription())) {
String t = fileName.getPath() + fileChooser.getFileFilter().getDescription();
fileName = new File(t);
}
fileName.canWrite();
if (fileName == null || fileName.getName().equals("")) {
JOptionPane.showMessageDialog(fileChooser, "無效的文件名", "無效的文件名", JOptionPane.ERROR_MESSAGE);
}
BufferedImage image = createImage(drawingArea);
try {
ImageIO.write(image, "png", fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
// 打開文件
public void openFile() {
// 文件選擇器
JFileChooser fileChooser = new JFileChooser();
// 設置文件顯示類型爲僅顯示文件
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
// 文件過濾器
JpgFilter jpg = new JpgFilter();
BmpFilter bmp = new BmpFilter();
PngFilter png = new PngFilter();
GifFilter gif = new GifFilter();
// 向用戶可選擇的文件過濾器列表添加一個過濾器。
fileChooser.addChoosableFileFilter(jpg);
fileChooser.addChoosableFileFilter(bmp);
fileChooser.addChoosableFileFilter(png);
fileChooser.addChoosableFileFilter(gif);
// 返回當前的文本過濾器,並設置成當前的選擇
fileChooser.setFileFilter(fileChooser.getFileFilter());
// 彈出一個 "Open File" 文件選擇器對話框
int result = fileChooser.showOpenDialog(MyFrame.this);
if (result == JFileChooser.CANCEL_OPTION) {
return;
}
// 得到選擇文件的名字
File fileName = fileChooser.getSelectedFile();
if (!fileName.getName().endsWith(fileChooser.getFileFilter().getDescription())) {
JOptionPane.showMessageDialog(MyFrame.this, "文件格式錯誤!");
return;
}
fileName.canRead();
if (fileName == null || fileName.getName().equals("")) {
JOptionPane.showMessageDialog(fileChooser, "無效的文件名", "無效的文件名", JOptionPane.ERROR_MESSAGE);
}
BufferedImage image;
try {
index = 0;
currentChoice = 0;
image = ImageIO.read(fileName);
drawingArea.createNewGraphics();
itemList[index].image = image;
itemList[index].board = drawingArea;
drawingArea.repaint();
index++;
currentChoice = 3;
drawingArea.createNewGraphics();
} catch (IOException e) {
e.printStackTrace();
}
}
//新建文件
public void newFile() {
index = 0;
currentChoice = 3;
color = Color.black;
stroke = 1;
drawingArea.createNewGraphics();
repaint();
}
// 創建image,由saveFile方法調用
// 將畫板內容畫到panelImage上
public BufferedImage createImage(DrawPanel panel) {
int width = MyFrame.this.getWidth();
int height = MyFrame.this.getHeight();
BufferedImage panelImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2D = (Graphics2D) panelImage.createGraphics();
g2D.setColor(Color.WHITE);
g2D.fillRect(0, 0, width, height);
g2D.translate(0, 0);
panel.paint(g2D);
g2D.dispose();
return panelImage;
}
// 文件過濾
class JpgFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
return f.getName().endsWith(".jpg");
}
@Override
public String getDescription() {
return ".jpg";
}
}
class BmpFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
return f.getName().endsWith(".bmp");
}
@Override
public String getDescription() {
return ".bmp";
}
}
class GifFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
return f.getName().endsWith(".gif");
}
@Override
public String getDescription() {
return ".gif";
}
}
class PngFilter extends FileFilter {
@Override
public boolean accept(File f) {
if (f.isDirectory())
return true;
return f.getName().endsWith(".png");
}
@Override
public String getDescription() {
return ".png";
}
}
}
class MyToolbar {
/**
* 工具欄初始化部分
*/
private ImageIcon[] icon; // 存放按鈕的圖片
private JButton[] btn_paint;// 定義各種繪圖的按鈕
private JComboBox<String> jfont;
private JComboBox<String> jfont_size;
private JToolBar toolbar; // 定義按鈕面板
private Checkbox btn_blod;// 粗體
private Checkbox btn_italic;// 斜體
// 將圖片資源的相對路徑存放於數組中,方便使用
private String images[] = { "/image/save.png", "/image/refresh.png", "/image/undo.png", "/image/pencil.png",
"/image/line.png", "/image/rectangle.png", "/image/rectangle3.png", "/image/oval.png",
"/image/oval2.png", "/image/circle.png", "/image/fillcircle.png", "/image/rectangle2.png",
"/image/rectangle4.png", "/image/triangle.png", "/image/pentagon.png", "/image/hexagon.png",
"/image/eraser.png", "/image/brush.png", "/image/font.png", };
private String tipText[] = { "保存", "清空", "撤銷", "鉛筆", "直線", "空心矩形", "填充矩形", "空心橢圓", "填充橢圓", "空心圓形", "填充圓形",
"空心圓角矩形", "填充圓角矩形", "三角形", "五邊形", "六邊形", "橡皮擦", "填充", "文本", "粗細" };
private String font[] = { "宋體", "隸書", "華文彩雲", "仿宋_GB2312", "華文行楷", "方正舒體" };
private String fontSize[] = { "8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36",
"48", "72" };
public MyToolbar() {
addToorbar();
}
public void addToorbar() {
btn_paint = new JButton[images.length];// 定義指定個數的按鈕
toolbar = new JToolBar("工具欄");// 實例化一個水平的工具標籤
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
toolbar.setBackground(new Color(195, 195, 195));
btn_blod = new Checkbox("粗體");
btn_italic = new Checkbox("斜體");
btn_blod.setBackground(new Color(195, 195, 195));
btn_italic.setBackground(new Color(195, 195, 195));
btn_blod.setPreferredSize(new Dimension(40, 30));
btn_italic.setPreferredSize(new Dimension(40, 30));
jfont_size = new JComboBox<String>(fontSize);
jfont_size.setPreferredSize(new Dimension(50, 30));
jfont = new JComboBox<String>(font);
jfont.setPreferredSize(new Dimension(100, 30));
icon = new ImageIcon[images.length];
// 設置按鈕圖標以及圖片
for (int i = 0; i < images.length; i++) {
// System.out.println(images[i]);//測試
btn_paint[i] = new JButton();
icon[i] = new ImageIcon(getClass().getResource(images[i]));
btn_paint[i].setIcon(icon[i]);
btn_paint[i].setToolTipText(tipText[i]);
btn_paint[i].setPreferredSize(new Dimension(28, 28));// 設置圖標大小
// btn_paint[i].setBorderPainted(false);// 去邊框
// btn_paint[i].setContentAreaFilled(false);
btn_paint[i].setBackground(Color.WHITE);
toolbar.add(btn_paint[i]);
}
toolbar.setFloatable(true);// 可以拖動
// toolbar.addSeparator();
// 字體格式:斜體,粗體
toolbar.add(btn_italic);
toolbar.add(btn_blod);
// 將動作偵聽器加入到按鈕裏面
for (int i = 2; i < images.length; i++) {
btn_paint[i].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (int j = 0; j < images.length; j++) {
// 如果按鈕被點擊。則設置相應的畫筆
if (e.getSource() == btn_paint[j]) {
currentChoice = j;
// System.out.println(images[j]);
// System.out.println(j);// 測試 監聽設置
drawingArea.createNewGraphics();
repaint();
}
}
}
});
}
btn_paint[0].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
menu.saveFile();
saved = 1;
}
});
btn_paint[1].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
menu.newFile();
}
});
btn_paint[2].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
drawingArea.undo();
}
});
// 添加監聽
btn_italic.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
italic = Font.ITALIC;
}
});
btn_blod.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
blodtype = Font.BOLD;
}
});
// 設置字體大小
toolbar.add(jfont_size);
jfont_size.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
fSize = Integer.parseInt(fontSize[jfont_size.getSelectedIndex()]);
// System.out.println(fSize);
}
});
// 設置字體
toolbar.add(jfont);
jfont.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
fontName = font[jfont.getSelectedIndex()];
// System.out.println(fontName);
}
});
MyFrame.this.add(toolbar, BorderLayout.NORTH);// 添加按鈕面板到容器中
}
}
}
Start類
package com.edu.nwafu.start;
import javax.swing.UIManager;
public class StartProject {
/**
* 啓動界面
*/
public static MyFrame wds;
public static void main(String[] args) {
// try {
// //調用Windows的文件系統
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// } catch (Exception e) {
//
// }
wds = new MyFrame("畫圖");
}
}
Shape類
package com.edu.nwafu.shape;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import javax.swing.JPanel;
public abstract class Shape implements Serializable {
/**
* 抽象父類,所有圖形類均要繼承該類
*/
private static final long serialVersionUID = 1L;
public int x1, y1, x2, y2;// 繪製圖形的座標
public Color color;// 畫筆顏色
public int width;// 畫筆粗細
public int currentChoice; // 形狀
public int length; // 鉛筆或橡皮擦的筆跡長度
public BufferedImage image; // 存放待打開圖片
public JPanel board; // 繪畫的畫板
public int fontSize;//字體大小
public String fontName;//字體
public String s;//文本
public int blodtype;//粗體
public int italic;//斜體
//抽象方法
public abstract void draw(Graphics2D g);
}
其他圖形類
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.util.Random;
/**
* 噴漆
* @author Administrator
*
*/
public class Brush extends Shape
{
/**
* 定義一個Brush類,繼承Shape類,實現刷子功能
*/
private static final long serialVersionUID = 1L;
private int fx[] = new int[100];
private int fy[] = new int[100];
public Brush(){
Random random = new Random();
for (int i = 0; i < 100; i++) {
fx[i] = random.nextInt(16)- 16;
fy[i] = random.nextInt(16)- 16;
//System.out.println("("+fx[i]+","+fy[i]+")");
}
}
public void draw(Graphics2D g) {
g.setPaint(color);;
g.setStroke(new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
for (int i = 0; i < 100; i++) {
double d = (double) fx[i];
double c = (double) fy[i];
g.drawLine((int) (x1 + d * Math.sin(d)), (int) (y1 + c * Math.sin(c)), (int) (x2 + d * Math.sin(d)),
(int) (y2 + c * Math.sin(c)));
}
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
/**
* 定義一個Circle類,繼承Shape類,用於繪製一個空心圓
* @author 沈仕瑞
*
*/
public class Circle extends Shape{
/**
*
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
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)));
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
/**
* 定義一個fillCircle類,繼承Shape類,用於繪製一個填充實心圓
* @author 沈仕瑞
*
*/
public class FillCircle extends Shape{
/**
*
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
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)));
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class FillOval extends Shape {
/**
* 定義一個fillOVal類,繼承Shape類,用於繪製一個填充橢圓
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class FillRect extends Shape {
/**
* 定義一個fillRect類,繼承Shape類,用於繪製一個填充矩形
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class FillRoundRect extends Shape {
/**
* 定義一個fillRoundRect類,繼承Shape類,用於繪製一個填充圓角矩形
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 50, 35);
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class Hexagon extends Shape {
/**
* 定義一個Hexagon類,繼承Shape類,用於繪製一個六邊形
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
int[] x = { Math.min(x1, x2) + Math.abs(x1 - x2) / 4, Math.min(x1, x2),
Math.min(x1, x2) + Math.abs(x1 - x2) / 4, Math.max(x1, x2) - Math.abs(x2 - x1) / 4, Math.max(x1, x2),
Math.max(x1, x2) - Math.abs(x2 - x1) / 4 };
int[] y = { Math.min(y1, y2), (y1 + y2) / 2, Math.max(y1, y2), Math.max(y1, y2), (y1 + y2) / 2,
Math.min(y1, y2) };
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawPolygon(x, y, 6);
}
}
package com.edu.nwafu.shape;
import java.awt.Graphics2D;
public class Images extends Shape{
/**
*
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g) {
g.drawImage(image, 0, 0, board);
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
public class Line extends Shape {
/**
* 定義一個Line類,繼承Shape類,用於繪製一個填充橢圓
*/
private static final long serialVersionUID = 1L;
public Line() {
}
//重寫父類的Draw方法,實現直線的繪製
public void draw(Graphics2D g) {
g.setColor(color);
g.setStroke(new BasicStroke(width));
g.drawLine(x1, y1, x2, y2);
//System.out.println("line has finshed");
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class Oval extends Shape{
/**
* 定義一個OVal類,繼承Shape類,用於繪製一個橢圓
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class Pencil extends Shape {
/**
* 定義一個Pencil類,繼承Shape類,用於鉛筆繪製
*/
private static final long serialVersionUID = 1L;
public Pencil(){
}
public void draw(Graphics2D g) {
g.setPaint(color);
//爲 Graphics2D 上下文設置 Stroke
g.setStroke(new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
//爲呈現算法設置單個首選項的值。
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawLine(x1, y1, x2, y2);
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class Pentagon extends Shape {
/**
* 定義一個Pentagon類,繼承Shape類,用於繪製一個五邊形
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
int[] x = { (x1 + x2) / 2, Math.min(x1, x2), Math.min(x1, x2) + Math.abs(x1 - x2) / 4,
Math.max(x1, x2) - Math.abs(x1 - x2) / 4, Math.max(x1, x2) };
int[] y = { Math.min(y1, y2), (int) (Math.min(y1, y2) + Math.abs(y1 - y2) / 2.5), Math.max(y1, y2),
Math.max(y1, y2), (int) (Math.min(y1, y2) + Math.abs(y1 - y2) / 2.5) };
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawPolygon(x, y, 5);
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class Rectangle extends Shape {
/**
* 定義一個Rectangle類,繼承Shape類,用於繪製一個矩形
*/
private static final long serialVersionUID = 1L;
public Rectangle(){
}
public void draw(Graphics2D g2d) {
g2d.setColor(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2),
Math.abs(y1 - y2));
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class RoundRect extends Shape {
/**
* 定義一個RoundRectangle類,繼承Shape類,用於繪製一個圓角矩形
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 50, 35);
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
/**
* 橡皮檫類
* @author 沈仕瑞
*
*/
public class Rubber extends Shape {
/**
* BasicStroke的幾個字段
* CAP_SQUARE 使用正方形結束未封閉的子路徑和虛線線段,
* 正方形越過線段端點,並延長等於線條寬度一半的距離。
* CAP_BUTT 無裝飾地結束未封閉的子路徑和虛線線段。
* CAP_ROUND 使用半徑等於畫筆寬度一半的圓形裝飾結束未封閉的子路徑和虛線線段。
* JOIN_BEVEL 通過直線連接寬體輪廓的外角,將路徑線段連接在一起。
*/
private static final long serialVersionUID = 1L;
public Rubber(){
}
public void draw(Graphics2D g) {
g.setPaint(Color.white);
g.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE , BasicStroke.JOIN_BEVEL));
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawLine(x1, y1, x2, y2);
}
}
package com.edu.nwafu.shape;
import java.awt.Font;
import java.awt.Graphics2D;
public class Text extends Shape// 文字
{
/**
* 定義一個Text類,繼承Shape類,用於文字輸入
*
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g) {
//Font(String name, int style, int size)
g.setColor(color);
g.setFont(new Font(fontName, italic+blodtype, fontSize));
if (s != null) {
g.drawString(s, x1, y1);
//System.out.println(fontName+" "+s+" "+fontSize );
}
}
}
package com.edu.nwafu.shape;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class Triangle extends Shape{
/**
* 定義一個Triangle類,繼承Shape類,用於繪製一個三角形
*/
private static final long serialVersionUID = 1L;
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
g2d.setStroke(new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
int[] x = { (x1 + x2) / 2, x1, x2 };
int[] y = { y1, y2, y2 };
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawPolygon(x, y, 3);
}
}
五、圖形資源