简介

作者简介:青铜码农,和大多数同学一样从零开始一步步学习,一步步积累。期待您的关注,让我们一起成长~注:本人学疏才浅,文章如有错误之处,敬请指正~

本章节内容简介:仿Windows系统自带的画图工具。此项目包含了设置画笔粗细、选择画笔颜色、选择背景颜色、绘制图像、清除图像、使用橡皮擦、简笔画窗口等功能。

所需技术如下图:

功能预览:

画图完整版视频

功能结构:

搭建项目

01导入资源

02创建DrawPictureFrame窗体类

03创建DrawPictureCanvas画板类

04添加鼠标画笔功能

05添加工具栏

06添加菜单栏

07实现添加水印功能

08添加鼠标效果

09添加简笔画对照窗口

实现过程

一、导入外部Jar包

DrawUtil.mr.Jar包中的类说明:

com.mr.util.BackgroundPanel:可以添加背景图片的面板类

com.mr.util.DrawImageUtil:绘图工具类,提供保存图片的方法

com.mr.util.FrameGetShape:兼容图形选择组件接口

com.mr.util.Shapes:图形选择组件返回的图形类

com.mr.util.ShapeWindow:图形选择组件类

二、创建可视窗体

创建DrawPictureFrame.java这个类,并将下面代码输入到类中:

​
/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类
​/*** 构造方法。*/public DrawPictureFrame() {ImageIcon imageIcon = new ImageIcon("src/img/picture/themeicon.png");Image image = imageIcon.getImage();setIconImage(image);// 设置窗体图标setResizable(false);// 窗体不能改变大小setTitle("画图(水印内容:[\" + shuiyin + \"])");// 设置标题,添加水印内容提示setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setBounds(500, 100, 574, 460);}
​/*** 启动程序*/public static void main(String[] args) {DrawPictureFrame frame = new DrawPictureFrame();frame.setVisible(true);}
} 

三、创建画板

import java.awt.*;
​
/*** @author WayLon* @create 2021-07-28 14:39* 备注:创建面板*/
public class DrawPictureCanvas extends Canvas {private Image image = null;
​/*** 设置画板中的图片** @param image - 画板中展示的图片对象*/public void setImage(Image image) {this.image = image;}
​/*** 重写paint()方法,在画布上绘制图像** @param g*/public void paint(Graphics g) {g.drawImage(image, 0, 0, null);}
​/*** 重写update()方法,这样可以解决屏幕闪烁的问题。** @param g*/public void update(Graphics g) {paint(g);}
​
}

并在DrawPictureFrame类中原有代码上新增一下代码:

第5-10、22、25-34行代码为新增代码

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类BufferedImage image = new BufferedImage(570, 390, BufferedImage.TYPE_INT_BGR);// 创建一个8位BGR颜色分量的图像Graphics gs = image.getGraphics();// 获得图像的绘图对象Graphics2D g = (Graphics2D) gs;// 将绘图图像转换为Graphics2D类型DrawPictureCanvas canvas = new DrawPictureCanvas();//创建画布对象Color forecolor = Color.BLACK;// 定义前景色,在这里可以把前景色理解为画笔颜色Color bacgroundColor = Color.WHITE;// 定义背景色/*** 构造方法。*/public DrawPictureFrame() {ImageIcon imageIcon = new ImageIcon("src/img/picture/themeicon.png");Image image = imageIcon.getImage();setIconImage(image);// 设置窗体图标setResizable(false);// 窗体不能改变大小setTitle("画图(水印内容:[\" + shuiyin + \"])");// 设置标题,添加水印内容提示setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setBounds(500, 100, 574, 460);init();// 组件初始化}
​/*** 组件初始化*/private void init() {g.setColor(bacgroundColor);g.fillRect(0, 0, 570, 390);// 用背景色填充整个画布g.setColor(forecolor);canvas.setImage(image);getContentPane().add(canvas);// 将画布添加到窗体容器默认布局的中部位置}/*** 启动程序*/public static void main(String[] args) {DrawPictureFrame frame = new DrawPictureFrame();frame.setVisible(true);}
}

四、添加鼠标画笔功能

下面的代码就是在DrawPictureFrame类已有代码的基础上,添加了鼠标监听功能,以便在拖动鼠标时,能够在窗体上绘制线条。

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类
/*此处省略相同代码*/int x = -1, y = -1;// 上一次鼠标绘制点的横、纵坐标boolean rubber = false;// 橡皮标识变量boolean drawShape = false;// 画图形标识变量/*** 构造方法。*/public DrawPictureFrame() {
/*此处省略相同代码*/init();// 组件初始化addListener();// 添加组件监听}
​/*** 为组件添加动作监听*/private void addListener() {// 画板添加鼠标移动事件监听canvas.addMouseMotionListener(new MouseMotionListener() {@Overridepublic void mouseDragged(final MouseEvent e) {// 当鼠标拖拽时if (x > 0 && y > 0) {// 如果X和Y存在·鼠标记录if (rubber) {// 如果橡皮标识为true,表示使用橡皮g.setColor(bacgroundColor);g.fillRect(x, y, 10, 10);// 在鼠标滑过的位置画填充的正方形} else {// 如果橡皮标识为false,表示用画笔画图g.drawLine(x, y, e.getX(), e.getY());// 在鼠标滑过的位置画直线}}x = e.getX();y = e.getY();canvas.repaint();// 更新画布}canvas.addMouseListener(new MouseAdapter() {// 当按键松开时@Overridepublic void mouseReleased (MouseEvent e){// 将记录上一次鼠标绘制点的横纵坐标恢复成-1x = -1;y = -1;}}}/*** 组件初始化*/private void init() {
/*此处省略相同代码*/}/*** 启动程序*/public static void main(String[] args) {
/*此处省略相同代码*/}
}

补充完这些代码之后,再运行main方法,就可以使用鼠标在空白区域画画了。

五、添加工具栏

1.添加工具栏组件

下面的代码就是在DrawPictureFrame类已有代码的基础上,添加以下代码:

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类
/*此处省略未发生变化的代码*/boolean drawShape = false;// 画图形标识变量
​private JToolBar toolBar;// 工具栏private JButton eraserButton;// 橡皮按钮private JToggleButton strokeButton1;// 细线按钮private JToggleButton strokeButton2;// 粗线按钮private JToggleButton strokeButton3;// 较粗按钮private JButton backgroundButton;// 背景色按钮private JButton foregroundButton;// 前景色按钮private JButton clearButton;// 清除按钮private JButton saveButton;// 保存按钮private JButton shapeButton;// 图形按钮/*** 构造方法。*/public DrawPictureFrame() {
/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {/*此处省略未发生变化的代码*/}/*** 组件初始化*/private void init() {
/*此处省略未发生变化的代码*/getContentPane().add(canvas);// 将画布添加到窗体容器默认布局的中部位置
​toolBar = new JToolBar();// 初始化工具栏toolBar.setFloatable(false);getContentPane().add(toolBar, BorderLayout.NORTH);// 工具栏添加到窗体最北位置
​saveButton = new JButton("保存");toolBar.add(saveButton);toolBar.addSeparator();// 添加分割条//初始化按钮对象,并添加文本内容strokeButton1 = new JToggleButton("细线");strokeButton1.setSelected(true);// 细线按钮处于被选中状态toolBar.add(strokeButton1);strokeButton2 = new JToggleButton("粗线");toolBar.add(strokeButton2);strokeButton3 = new JToggleButton("较粗");
​ButtonGroup strokeGroup = new ButtonGroup();// 画笔粗细按钮组,保证同时只有一个按钮被选中strokeGroup.add(strokeButton1);strokeGroup.add(strokeButton2);strokeGroup.add(strokeButton3);toolBar.add(strokeButton3);toolBar.addSeparator();backgroundButton = new JButton("背景颜色");toolBar.add(backgroundButton);foregroundButton = new JButton("前景颜色");toolBar.add(foregroundButton);toolBar.addSeparator();
​clearButton = new JButton("清除");toolBar.add(clearButton);
​eraserButton = new JButton("橡皮擦");toolBar.add(eraserButton);
}/*** 启动程序*/public static void main(String[] args) {
/*此处省略未发生变化的代码*/}
}

运行一下就可以看到工具栏

2.实现调整画笔粗细功能

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类
/*此处省略未发生变化的代码*//*** 构造方法。*/public DrawPictureFrame() {
/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {/*此处省略未发生变化的代码*/// 细线按钮添加动作监听strokeButton1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_stroke1_actionPerformed();}});
​// 粗线按钮添加动作监听strokeButton2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_stroke2_actionPerformed();}});
​// 较粗线按钮添加动作监听strokeButton3.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_stroke3_actionPerformed();}});}/*** 组件初始化*/private void init() {/*此处省略未发生变化的代码*/}// 细线按钮及其菜单项所触发的动作事件private void do_stroke1_actionPerformed() {//  声明画笔的属性粗细为1像素,线条末端无修饰,折线处呈尖角BasicStroke bs = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);g.setStroke(bs);strokeButton1.setSelected(true);//这行的选中代码显得有点多余,但是后头的菜单项需要使用到}
​// 粗线按钮及其菜单项所触发的动作事件private void do_stroke2_actionPerformed() {//  声明画笔的属性粗细为2像素,线条末端无修饰,折线处呈尖角BasicStroke bs = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);g.setStroke(bs);strokeButton2.setSelected(true);//这行的选中代码显得有点多余,但是后头的菜单项需要使用到}
​// 较粗按钮及其菜单项所触发的动作事件private void do_stroke3_actionPerformed() {//  声明画笔的属性粗细为4像素,线条末端无修饰,折线处呈尖角BasicStroke bs = new BasicStroke(4, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);g.setStroke(bs);strokeButton3.setSelected(true);//这行的选中代码显得有点多余,但是后头的菜单项需要使用到}/*** 启动程序*/public static void main(String[] args) {
/*此处省略未发生变化的代码*/}
}

自己运行一下看下效果叭、

3.实现添加颜色功能

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类
/*此处省略未发生变化的代码*//*** 构造方法。*/public DrawPictureFrame() {
/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {
/*此处省略未发生变化的代码*/// 背景颜色按钮添加动作监听backgroundButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_background_actionPerformed();}});
​// 前景色按钮添加动作监听foregroundButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_foreground_actionPerformed();}});}/*** 组件初始化*/private void init() {/*此处省略未发生变化的代码*/}// 背景色按钮及其菜单项所触发的动作事件private void do_background_actionPerformed() {// 打开选择颜色对话框,参数依次为父窗体,标题、默认选中的颜色青色Color bgColor = JColorChooser.showDialog(DrawPictureFrame.this, "选择颜色对话框", Color.CYAN);if (bgColor != null) {bacgroundColor = bgColor;// 将选中的颜色赋给背景色变量}// 背景色按钮也更换为这种背景颜色backgroundButton.setBackground(bacgroundColor);g.setColor(bacgroundColor);// 绘图工具使用背景色g.fillRect(0, 0, 570, 390);// 画一个背景颜色的方形,填满整个画布g.setColor(forecolor);// 绘图工具使用前景色canvas.repaint();}
​// 前景色按钮及其菜单项所触发的动作事件private void do_foreground_actionPerformed() {Color fColor = JColorChooser.showDialog(DrawPictureFrame.this, "选择颜色对话框", Color.CYAN);if (fColor != null) {forecolor = fColor;// 将选择的颜色赋值给前景色变量}// 前景色按钮的文字也更换为这种颜色foregroundButton.setForeground(forecolor);g.setColor(forecolor);// 绘图工具使用前景色}/*** 启动程序*/public static void main(String[] args) {
/*此处省略未发生变化的代码*/}
}

运行结果:

4.实现清除图像功能
在DrawPictureFrame类中的addListener()方法中补充以下代码:

        // 清除按钮添加动作监听clearButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {g.setColor(bacgroundColor);// 绘图工具使用背景色g.fillRect(0, 0, 570, 390);// 画一个背景色的方形,填满整个画布g.setColor(forecolor);// 绘图工具使用前景色canvas.repaint();}});
​eraserButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if (eraserButton.getText().equals("橡皮擦")) {rubber = true;eraserButton.setText("画图");} else {rubber = false;eraserButton.setText("橡皮擦");g.setColor(forecolor);}}});
​

运行结果:

5.实现绘制图形功能

首先让DrawPictureFrame类实现接口:FrameGetShape接口

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类
/*此处省略未发生变化的代码*/boolean rubber = false;// 橡皮标识变量// 上为原有代码,为了方便下面新代码寻找位置插入boolean drawShape = false;// 画图形标识变量Shapes shapes;// 绘画的图形
​
/*此处省略未发生变化的代码*/
​/*** 构造方法。*/public DrawPictureFrame() {
/*此处省略未发生变化的代码*/}
​/*** 启动程序*/public static void main(String[] args) {
/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {
/*此处省略未发生变化的代码*/// 当按键按下时@Overridepublic void mousePressed(MouseEvent e) {if (drawShape) {// 如果此时鼠标画的是图形switch (shapes.getType()) {// 判断图形的种类case Shapes.YUAN:// 如果是圆形// 计算坐标,让鼠标处于图形中的中心位置int yuanX = e.getX() - shapes.getWidth() / 2;int yuanY = e.getY() - shapes.getHeigth() / 2;// 创建圆形图形并指定坐标和宽高Ellipse2D yuan = new Ellipse2D.Double(yuanX, yuanY, shapes.getWidth(), shapes.getHeigth());g.draw(yuan);//画图工具画此圆形break;case Shapes.FANG:int fangX = e.getX() - shapes.getWidth() / 2;int fangY = e.getY() - shapes.getHeigth() / 2;// 创建方形图形并指定坐标和宽高Rectangle2D fang = new Rectangle2D.Double(fangX, fangY, shapes.getWidth(), shapes.getHeigth());g.draw(fang);// 画图工具画此方形break;}canvas.repaint();// 画图形标识变量为false,说明现在鼠标画的是图形而不是线条drawShape = false;}}
​// 图形按钮添加动作监听shapeButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {// 创建图形选择组件ShapeWindow shapeWindow = new ShapeWindow(DrawPictureFrame.this);int shapeButtonWidth = shapeButton.getWidth();// 获取图形按钮宽度int shapeWindowWidth = shapeWindow.getWidth();// 获取图形按钮高度int shapeButtonX = shapeButton.getX();// 获取图形按钮,横坐标int shapeButtonY = shapeButton.getY();// 获取图形按钮,纵坐标// 计算图形组件横坐标,让组件与图形按钮居中对齐int shapeWindowX = getX() + shapeButtonX - (shapeWindowWidth - shapeButtonWidth) / 2;// 计算图形,组件纵坐标,让组件显示在图形按钮下方int shapeWindowY = getY() + shapeButtonY + 80;////设置图形组件坐标位置shapeWindow.setLocation(shapeWindowX, shapeWindowY);shapeWindow.setVisible(true);// 图形组件可见}});
​/*** FrameGetShape接口实现类,用于获得图形空间返回的被选中的图形*/@Overridepublic void getShape(Shapes shapes) {this.shapes = shapes;// 将返回的图形对象赋给类的全局变量drawShape = true;// 画图形标识变量为true,说明现在鼠标画的是图形而不是线条}}
​/*** 组件初始化*/private void init() {/*此处省略未发生变化的代码*/eraserButton = new JButton("橡皮擦");toolBar.add(eraserButton);//上两行为原有代码,,为了方便下面新代码寻找位置插入shapeButton = new JButton("图形");toolBar.add(shapeButton);}
}

运行结果:

5.实现保存图片功能

将绘制好的图像保存成图片文件,需要用到一个外部的jar文件,就是最开始已经导入的DrawUtil.mr.jar文件。
在DrawPictureFrame类中的addListener()方法中补充以下代码:

        // 保存按钮添加动作监听saveButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_save_actionPerformed();}});

单击保存按钮之后,弹出保存图片对话框:

六、添加菜单栏

1.添加菜单栏组件

新增代码如下:

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类/*此处省略未发生变化的代码*/
​private JMenuItem strokeMenuItem1;// 细线菜单private JMenuItem strokeMenuItem2;// 粗线菜单private JMenuItem strokeMenuItem3;// 较粗菜单private JMenuItem clearMenuItem;// 清除菜单private JMenuItem helpMenuItem;// 帮助菜单private JMenuItem foregroundMenuItem;// 前景色菜单private JMenuItem backgroundMenuItem;// 背景色菜单private JMenuItem eraserMenuItem;// 橡皮擦菜单private JMenuItem exitMenuItem;// 退出菜单private JMenuItem saveMenuItem;// 保存菜单/*** 构造方法。*/public DrawPictureFrame() {/*此处省略未发生变化的代码*/}
​/*** 启动程序*/public static void main(String[] args) {/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {/*此处省略未发生变化的代码*/}
​/*** 组件初始化*/private void init() {/*此处省略未发生变化的代码*/shapeButton = new JButton("图形");toolBar.add(shapeButton);//上两行为原有代码,,为了方便下面新代码寻找位置插入JMenuBar menuBar = new JMenuBar();// 创建菜单栏setJMenuBar(menuBar);// 窗体载入菜单栏
​JMenu systemMenu = new JMenu("系统");// 初始化菜单menuBar.add(systemMenu);// 菜单栏添加菜单对象
​saveMenuItem = new JMenuItem("保存");// 初始化菜单项systemMenu.add(saveMenuItem);// 菜单添加菜单项systemMenu.addSeparator();// 添加分割条exitMenuItem = new JMenuItem("退出");systemMenu.add(exitMenuItem);
​JMenu strokeMenu = new JMenu("线型");menuBar.add(strokeMenu);strokeMenuItem1 = new JMenuItem("细线");strokeMenu.add(strokeMenuItem1);strokeMenuItem2 = new JMenuItem("粗线");strokeMenu.add(strokeMenuItem2);strokeMenuItem3 = new JMenuItem("较粗");strokeMenu.add(strokeMenuItem3);
​JMenu colorMenu = new JMenu("颜色");menuBar.add(colorMenu);backgroundMenuItem = new JMenuItem("背景颜色");colorMenu.add(backgroundMenuItem);foregroundMenuItem = new JMenuItem("前景颜色");colorMenu.add(foregroundMenuItem);
​
​JMenu editMenu = new JMenu("编辑");menuBar.add(editMenu);clearMenuItem = new JMenuItem("清除");editMenu.add(clearMenuItem);eraserMenuItem = new JMenuItem("橡皮擦");editMenu.add(eraserMenuItem);
​
​JMenu helpMenu=new JMenu("帮助");menuBar.add(helpMenu);helpMenuItem =new JMenuItem("说明");helpMenu.add(helpMenuItem);}
}

​效果如下:

2.给菜单项添加点击事件

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类/*此处省略未发生变化的代码*//*** 构造方法。*/public DrawPictureFrame() {/*此处省略未发生变化的代码*/}
​/*** 启动程序*/public static void main(String[] args) {/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {/*此处省略未发生变化的代码*/
​// 退出菜单栏添加动作监听exitMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.exit(0);// 程序关闭}});
​// 橡皮擦菜单栏添加动作监听eraserMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if (eraserMenuItem.getText().equals("橡皮擦")) {rubber = true;eraserMenuItem.setText("画图");eraserButton.setText("画图");} else {rubber = false;eraserMenuItem.setText("橡皮擦");eraserButton.setText("橡皮擦");g.setColor(forecolor);}}});
​//清除菜单添加动作监听clearMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {g.setColor(bacgroundColor);g.fillRect(0, 0, 570, 390);g.setColor(forecolor);canvas.repaint();}});
​//细线菜单添加动作监听strokeMenuItem1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_stroke1_actionPerformed();}});
​// 粗线菜单添加动作监听strokeMenuItem2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_stroke2_actionPerformed();}});
​// 较粗线菜单添加动作监听strokeMenuItem3.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_stroke3_actionPerformed();}});
​// 前景色菜单添加动作监听foregroundMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_foreground_actionPerformed();}});
​// 背景色菜单添加动作监听backgroundMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_background_actionPerformed();}});
​//保存菜单添加动作监听saveMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {do_save_actionPerformed();}});
​helpMenuItem.addActionListener(new ActionListener() {@Overridepublic 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)画布用于图形绘制,使用鼠标选中要绘制的图形即可进行绘制。", "使用说明", JOptionPane.PLAIN_MESSAGE);}});}
​/*** 组件初始化*/private void init() {/*此处省略未发生变化的代码*/}
}

3.实现添加水印功能

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类/*此处省略未发生变化的代码*/
​private JMenuItem shuiyinMenuItem;// 水印菜单private String shuiyin = "";// 水印字符内容/*** 构造方法。*/public DrawPictureFrame() {/*此处省略未发生变化的代码*/}
​/*** 启动程序*/public static void main(String[] args) {/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {/*此处省略未发生变化的代码*/
​// 水印菜单项添加动作监听shuiyinMenuItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e){shuiyin = JOptionPane.showInputDialog(DrawPictureFrame.this, "你想添加什么水印?");if (null == shuiyin) {shuiyin = "";} else {setTitle("画图(水印内容:[" + shuiyin + "])");// 设置标题,添加水印内容提示}}});
​}
​/*此处省略未发生变化的代码*/private void addWatermark() {if (!"".equals(shuiyin.trim())) {g.rotate(Math.toRadians(-30));// 将图片旋转-30度Font font = new Font("楷体", Font.BOLD, 32);g.setFont(font);g.setColor(Color.GRAY);AlphaComposite alphaComposite = AlphaComposite.SrcOver.derive(0.4f);// 设置透明效果g.setComposite(alphaComposite);// 使用透明效果g.drawString(shuiyin, 150, 500);// 绘制文字canvas.repaint();g.rotate(Math.toRadians(30));// 将旋转的图片再转回来alphaComposite = AlphaComposite.SrcOver.derive(1f);// 不透明效果g.setComposite(alphaComposite);g.setColor(forecolor);// 画笔恢复之前颜色}}/*** 组件初始化*/private void init() {/*此处省略未发生变化的代码*/}
}

效果图如下:

4.添加鼠标图标效果

鼠标光标如果一直保持一个样式,会给操作带来了诸多不便,会很难分清当前拿的是画笔还是橡皮。

下面的代码就是在DrawPictureFrame类已有代码的基础上,添加以下代码:

 @Overridepublic void mouseMoved(MouseEvent e) {if (rubber) {// 设置鼠标指针的形状为图片Toolkit kit = Toolkit.getDefaultToolkit();// 获得系统默认的组件工具包// 利用工具包获取图片Image img = kit.createImage("src/img/鼠标橡皮.png");// 利用工具包创建一个自定义的光标对象// 参数为图片、光标热点和光标描述字符串Cursor c = kit.createCustomCursor(img, new Point(0, 0), "clear");setCursor(c);// 使用自定义的光标} else {setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));}}});// 工具栏添加鼠标移动监听toolBar.addMouseMotionListener(new MouseMotionAdapter() {@Overridepublic void mouseMoved(MouseEvent e) {// 设置鼠标指针的形状为默认光标setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));}});

效果图如下:

七、添加简笔画对照窗口

做一个小窗口来展示已经画好的简笔画,可以让读者模仿画出来。

1.创建显示简笔画的窗体

首先创建PictureWindow.java这个类:

import com.mr.util.BackgroundPanel;
​
import javax.imageio.plugins.jpeg.JPEGHuffmanTable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
​
/*** @author WayLon* @create 2021-07-28 21:08* 备注:简笔画展示窗体*/
public class PictureWindow extends JWindow {File list[];// 图片文件数组int index;// 当前选中图片的索引DrawPictureFrame frame;// 父窗体private JButton changeButton;// 更换图片按钮private JButton hiddenButton;// 隐藏按钮private BackgroundPanel centerPanel;// 展示图片的带背景图面板
​/*** 构造方法** @param frame - 父窗体*/public PictureWindow(DrawPictureFrame frame) {this.frame = frame;setSize(400, 460);init();// 初始化窗体组件addListener();// 给组件添加加监听}
​/*** 添加监听*/private void addListener() {// 隐藏按钮添加动作监听hiddenButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {setVisible(false);frame.initShowPicButton();// 父类窗体还原简笔画按钮的文本内容}});
​// 更换图片按钮添加动作监听changeButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {centerPanel.setImage(getListImage());}});}
​/*** 组件初始化方法*/private void init() {Container c = getContentPane();//获取窗体主容器File dir = new File("src/img/picture");// 创建简笔画素材文件夹对象list = dir.listFiles();// 获取文件夹里的所有文件// 初始化背景面板,使用图片文件夹里的第1张简笔画centerPanel = new BackgroundPanel(getListImage());c.add(centerPanel, BorderLayout.CENTER);// 背景面板放到主容器中部FlowLayout flow = new FlowLayout(FlowLayout.RIGHT);// 创建右对齐的流布局flow.setHgap(20);// 水平间隔20像素JPanel southPanel = new JPanel();// 创建南部面板southPanel.setLayout(flow);// 南部面板使用刚才创建好的流布局changeButton = new JButton("更换图片");// 实例化更换图片的按钮southPanel.add(changeButton);// 南部面板添加按钮hiddenButton = new JButton("隐藏");// 实例化隐藏按钮southPanel.add(hiddenButton);// 南部面板添加按钮c.add(southPanel, BorderLayout.SOUTH);// 南部面板放到主容器的南部位置}
​/*** 获取图片文件夹下的图片,每次调用此方法都会获得不同的文件对象* @return 返回图片对象*/private Image getListImage() {String imgPath=list[index].getAbsolutePath();// 获取当前索引下的图片文件路径ImageIcon imageIcon=new ImageIcon(imgPath);// 获取此图片文件的图标对象index++;if (index>=list.length){index=0;}return imageIcon.getImage();// 获取图标对象的图片对象}
}

2.实现简笔画窗体与主窗体互相关联

①修改DrawPictureFrame类

在主窗体中添加简笔画展示窗体对象,并添加”展开简笔画“按钮;添加initShowPicButton()方法,当在简笔画窗体中单击”隐藏“按钮时,调用此方法,可使主窗体按钮上的”隐藏简笔画“变回”展开简笔画“字样

/*** 画图主窗体。*/
public class DrawPictureFrame extends JFrame {// 继承窗体类
/*此处省略未发生变化的代码*/private PictureWindow pictureWindow;// 简笔画展示窗体private JButton showPicButton;// 展开简笔画的按钮
​/*** 构造方法。*/public DrawPictureFrame() {
/*此处省略未发生变化的代码*/}
​/*** 启动程序*/public static void main(String[] args) {
/*此处省略未发生变化的代码*/}
​/*** 为组件添加动作监听*/private void addListener() {/*此处省略未发生变化的代码*/// 展示简笔画按钮添加动作监听showPicButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e){boolean isVisible = pictureWindow.isVisible();// 获取简笔画展示窗体的可见状态if (isVisible) {showPicButton.setText("展开简笔画");// 修改按钮的文本pictureWindow.setVisible(false);// 隐藏简笔画展示窗体} else {showPicButton.setText("隐藏简笔画");// 重新指定简笔画展示窗体的显示位置pictureWindow.setLocation(getX() - pictureWindow.getWidth() - 5, getY());pictureWindow.setVisible(true);// 简笔画展示窗体可见}}});}
​/*** 恢复展开简笔画按钮的文本内容,此方法供简笔画画板的隐藏按钮调用*/public void initShowPicButton() {showPicButton.setText("展开简笔画");}
​
​// 保存按钮及其菜单项所触发的动作事件private void do_save_actionPerformed() {/*此处省略未发生变化的代码*/}// 背景色按钮及其菜单项所触发的动作事件private void do_background_actionPerformed() {}
​// 前景色按钮及其菜单项所触发的动作事件private void do_foreground_actionPerformed() {/*此处省略未发生变化的代码*/}
​// 细线按钮及其菜单项所触发的动作事件private void do_stroke1_actionPerformed() {/*此处省略未发生变化的代码*/}
​// 粗线按钮及其菜单项所触发的动作事件private void do_stroke2_actionPerformed() {/*此处省略未发生变化的代码*/}
​// 较粗按钮及其菜单项所触发的动作事件private void do_stroke3_actionPerformed() {/*此处省略未发生变化的代码*/}
​private void addWatermark() {/*此处省略未发生变化的代码*/}/*** 组件初始化*/private void init() {/*此处省略未发生变化的代码*/toolBar.setFloatable(false);getContentPane().add(toolBar, BorderLayout.NORTH);// 工具栏添加到窗体最北位置// 上二行为原有代码,为了方便下面新代码寻找位置插入showPicButton = new JButton("展开简笔画");toolBar.add(showPicButton);// 工具栏添加按钮/*此处省略未发生变化的代码*/helpMenu.add(helpMenuItem);// 上一行为原有代码,为了方便下面新代码寻找位置插入pictureWindow = new PictureWindow(DrawPictureFrame.this);// 创建简笔画展示面板,并将本类当作它的父窗体}
}

效果图如下:

至此,该项目大功告成。

完整源码及素材链接:https://download.csdn.net/download/Waylon_Ma/20625199

我是码龙,如果我的文章对你有帮助,请点个 

Java项目——画图软件相关推荐

  1. Java实现画图软件(Swing)

    目标:使用Java中的GUI工具包Swing实现画图软件的创建 UI界面 首先要创建出这样的样子的界面,这就要用到JFrame类,创建一个窗体对象,然后将所有的组件(按钮.画布等)放入窗体对象中. p ...

  2. java大作业画图软件,模仿微软Paint、PowerPoint(含报告、只因你太美动画)

    画图软件 含报告.附送java文档.只因你太美动画(donghua49.txt) 特色动画功能b站演示地址https://www.bilibili.com/video/BV1iv4y1v7gx/?vd ...

  3. 如何使用eclipse软件创建一个Java项目?

    同学们在参加Java的时候老师肯定会教给你们如何去创建一个项目,这里怕有些同学没记住,所以单独为大家分享一篇如何使用eclipse软件创建一个Java项目教程,感觉有用的话收藏转发一下~ eclips ...

  4. 开源项目推荐:OpenGL/Vulkan/Cairo/Skia/angle/VTK/OpenVG/MyPaint/GIMP/Krita/Pencil2D/inkspace/enve等绘图库或画图软件

    绘图引擎简介 Windows环境下二维绘图引擎有多种选择:GDI.GDI+.DirectDraw.Qt/QPainter.Agg.Cairo.skia.Direct2D.Direct3D.OpenGL ...

  5. 画图软件Java实现(面向对象程序设计)

    画图软件 一.需求 利用面向对象的思想,设计并实现一个画图软件.实现基本的图形绘制功能.文本绘制功能.橡皮檫功能.撤销功能以及图片的存取功能,画图软件具有美观的用户界面.使用户可以绘制直线.曲线.矩形 ...

  6. Java项目一(案例):家庭收支记账软件

    Java项目一(案例):家庭收支记账软件 项目概述 软件功能 项目说明 涉及Java知识点 软件需求说明 程序代码示例 FamilyAccount.class文件 自定义Utility.class工具 ...

  7. Java画图软件制作

    实现了简单的电脑画图软件,代码如下: import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.CardLa ...

  8. JAVA项目的打包及生成.exe文件或者打包安装软件

    总体思路是先打成jar再把jar打成exe.主要看1.3和2.3里的内容就可以了. 1.将项目打成jar: 1.1要将项目打包成jar文件,方法很多,可以用Eclipse自带的打包工具Ant打包,也可 ...

  9. java robot机器人控制电脑画图软件实现画个圆圈demo

    前期准备 上一篇文章<java robot机器人控制windows打开浏览器,访问指定网址> 打开电脑画图软件,以window自带的画图软件为例,打开后点击最大化. java代码示例,放在 ...

最新文章

  1. 【Arduino基础教程】FSR402力敏电阻器
  2. 特斯拉炫技现场:电驴、行人、快递车,中国的小路难不倒Autopilot自动驾驶
  3. python教程list类型_Python数据类型之list相关常用操作
  4. VisualStudio异常处理 —— LNK1112 模块计算机类型“x64”与目标计算机类型“X86”冲突
  5. java中while空循环_java – 实现空while循环以保持控制的更好方法
  6. js判断数组中重复元素并找出_javascript查找数组中重复元素的方法
  7. C++ 中的动态库和静态库(Windows)
  8. 算法:回文数字9. Palindrome Number
  9. 2021-09-08321. 拼接最大数 单调栈
  10. P,NP,NPC,NP-HARD 图片基于P!=NP
  11. 关于pycharm中代码为灰色以及如何调整代码检查级别的问题
  12. 【Matlab车牌识别】BP神经网络车牌识别【含GUI源码 669期】
  13. English Pod 听力学习之路 C41 - C68
  14. 国内家具行业数据浅析
  15. fedora安装视频播放器
  16. 前端缓存【web缓存】
  17. JSP内置对象Session——setAttribute/getAttibute/removeAttribute
  18. telegram协议电报群组采集,群用户提取,私发消息,群拉人,关键词监控回复等引流自动化
  19. 快播转型,用户且用切珍惜
  20. PMP每日一练 | 考试不迷路-9.13(包含敏捷+多选)

热门文章

  1. 30岁后你会站在哪里?(转)
  2. escape() 函数
  3. 银行怎样处理坏账和贷款展期
  4. 高额补贴!武汉市科技型企业保证保险贷款补贴申报条件、流程和材料
  5. office里面各种快捷键代表的单词
  6. python匿名函数的作用_Python匿名函数 Lambda表达式作用
  7. 基于C-V2X的闯红灯预警方法与流程
  8. 顺丰gis产品经理_2018顺丰科技面试经验(产品经理,gis产品经理等)
  9. 测试游戏战地1配置软件,《战地1》PC版性能测试 太吃CPU、对显卡要求不高
  10. APP软件产品运营推广