所需技术如下图:
功能预览:
画图完整版视频
功能结构:
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() {
@Override
public 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() {
// 当按键松开时
@Override
public void mouseReleased (MouseEvent e){
// 将记录上一次鼠标绘制点的横纵坐标恢复成-1
x = -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() {
@Override
public void actionPerformed(ActionEvent e) {
do_stroke1_actionPerformed();
}
});
// 粗线按钮添加动作监听
strokeButton2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
do_stroke2_actionPerformed();
}
});
// 较粗线按钮添加动作监听
strokeButton3.addActionListener(new ActionListener() {
@Override
public 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() {
@Override
public void actionPerformed(ActionEvent e) {
do_background_actionPerformed();
}
});
// 前景色按钮添加动作监听
foregroundButton.addActionListener(new ActionListener() {
@Override
public 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() {
@Override
public void actionPerformed(ActionEvent e) {
g.setColor(bacgroundColor);// 绘图工具使用背景色
g.fillRect(0, 0, 570, 390);// 画一个背景色的方形,填满整个画布
g.setColor(forecolor);// 绘图工具使用前景色
canvas.repaint();
}
});
eraserButton.addActionListener(new ActionListener() {
@Override
public 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() {
/*此处省略未发生变化的代码*/
// 当按键按下时
@Override
public 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() {
@Override
public 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接口实现类,用于获得图形空间返回的被选中的图形
*/
@Override
public 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() {
@Override
public 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() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);// 程序关闭
}
});
// 橡皮擦菜单栏添加动作监听
eraserMenuItem.addActionListener(new ActionListener() {
@Override
public 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() {
@Override
public void actionPerformed(ActionEvent e) {
g.setColor(bacgroundColor);
g.fillRect(0, 0, 570, 390);
g.setColor(forecolor);
canvas.repaint();
}
});
//细线菜单添加动作监听
strokeMenuItem1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
do_stroke1_actionPerformed();
}
});
// 粗线菜单添加动作监听
strokeMenuItem2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
do_stroke2_actionPerformed();
}
});
// 较粗线菜单添加动作监听
strokeMenuItem3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
do_stroke3_actionPerformed();
}
});
// 前景色菜单添加动作监听
foregroundMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
do_foreground_actionPerformed();
}
});
// 背景色菜单添加动作监听
backgroundMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
do_background_actionPerformed();
}
});
//保存菜单添加动作监听
saveMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
do_save_actionPerformed();
}
});
helpMenuItem.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)画布用于图形绘制,使用鼠标选中要绘制的图形即可进行绘制。", "使用说明", 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() {
@Override
public 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类已有代码的基础上,添加以下代码:
登录后复制
@Override
public 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() {
@Override
public 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() {
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
frame.initShowPicButton();// 父类窗体还原简笔画按钮的文本内容
}
});
// 更换图片按钮添加动作监听
changeButton.addActionListener(new ActionListener() {
@Override
public 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() {
@Override
public 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);// 创建简笔画展示面板,并将本类当作它的父窗体
}
}
效果图如下:
至此,该项目大功告成。
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删