1. 创建shouui方法
要想绘制一个可见的画板,我们需要用到Java类库中的Jframe类来帮助我们创建
首先,我们先创建shouui()方法,并且在main中调用此方法
public class UI{ public void showui(){ } public static void main(String[] args) { UI ui = new UI(); ui.showui(); } }
这样,我们在shouui()中写的代码就可以在main中运行了
创意画板项目需要java.lang包下的swing类和awt类,所以导入进来(导包)
import javax.swing.*; import java.awt.*;
2.创建画板
然后就是创建画板了
public void showui(){ JFrame jf = new JFrame(); //尺寸,标题,居中,关闭,可见 jf.setSize(1500,800); jf.setTitle("创意画板"); jf.setLocationRelativeTo(null);//窗体在绘制时处于屏幕中央 jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//点击窗体右上角的x可以结束程序 jf.setVisible(true); }
这样,我们就获得了一张这样的画板
当我们点击右上角的x时,程序结束
3.布局管理器
现在,我们开始丰富这个窗口吧
一个成熟的创意画板应该拥有很多功能,而选择不同的功能就需要不同的按钮,所以我们先给画板添加按钮
要添加按钮,就要介绍下布局管理器了
//流式布局管理器 // FlowLayout flowLayout = new FlowLayout(); // jf.setLayout(flowLayout); //边框布局管理器 BorderLayout borderLayout = new BorderLayout(); jf.setLayout(borderLayout);
布局管理器,顾名思义,管理布局的。按钮的布局我们就是通过布局管理器进行布局管理,其中,流式布局管理器的布局特点是:从第一行开始分布,居中显示,如果一行不够则在第一行填满的情况下用第二行(居中显示)
而边框布局管理器则是将画板分为五块,每一块内部都是流式布局管理
流式布局管理器的用法具体为
//面板对象 JPanel westjPanel = new JPanel(); // westjPanel.setBackground(Color.WHITE); westjPanel.setPreferredSize(new Dimension(120,0)); jf.add(westjPanel,BorderLayout.WEST); JPanel eastjPanel = new JPanel(); // eastjPanel.setBackground(Color.WHITE); eastjPanel.setPreferredSize(new Dimension(50,0)); jf.add(eastjPanel,BorderLayout.EAST); JPanel centerjPanel = new JPanel(); // centerjPanel.setBackground(Color.WHITE); jf.add(centerjPanel,BorderLayout.CENTER); JPanel southjPanel = new JPanel(); // southjPanel.setBackground(Color.WHITE); southjPanel.setPreferredSize(new Dimension(0,40)); jf.add(southjPanel,BorderLayout.SOUTH);
其中,南北只能设置高度,东西只能设置宽度,中间是剩余的空间,无法设置(设置了也没有用)
4.添加按钮
由于我们会添加很多按钮,而每一次添加按钮都会进行重复的添加操作,所以我创建了一个集合用于存放按钮的名字,再用增强for循环遍历集合,在循环内部进行添加操作
ArrayList<String> functionlist = new ArrayList(); functionlist.add("直线"); functionlist.add("三角形"); functionlist.add("任意多边形"); for(String f : functionlist){ JButton a = new JButton(f); westjPanel.add(a); }
现在,我们的画板上就有按钮了
5.添加监听器
但是,现在我们点击按钮,什么事情都不会发生,这是因为我们还没有给按钮添加相对应的监听器,现在我们来添加监听器
我们这里会用到三种监听器
新建mouselistener类实现MouseListener,ActionListener,MouseMotionListener接口,并且实现相应的抽象方法
public class mouselistener implements MouseListener,ActionListener,MouseMotionListener { @Override public void actionPerformed(ActionEvent e) { //点击按钮 } @Override public void mouseClicked(MouseEvent e) { //点击 } @Override public void mousePressed(MouseEvent e) { //按下 } @Override public void mouseReleased(MouseEvent e) { //释放 } @Override public void mouseEntered(MouseEvent e) { //进入 } @Override public void mouseExited(MouseEvent e) { //离开 } @Override public void mouseDragged(MouseEvent e) { //鼠标拖动事件 } @Override public void mouseMoved(MouseEvent e) { //鼠标移动事件 } }
现在,当我们需要在画板的哪个部分实现什么功能的时候,只需要将此部分添加对应功能需要的监听器,然后在事件内部写对应的代码就行啦
比如,我想实现按下直线按钮后,就可以在centerjPanel上画直线的功能。
首先,按按钮事件是由接口ActionListener中actionPerformed()方法实现的。
其次,画直线需要你点击画板,然后移动鼠标松开,绘制直线,当然你也可以选择不同的方式。此处的方式会用到MouseListener中mousePressed(),和mouseReleased()方法
所以我们在UI类中新建窗口鼠标监听器
mouselistener mouselistener = new mouselistener();
并且在增强for循环中添加鼠标监听器
for(String f : functionlist){ JButton a = new JButton(f); westjPanel.add(a); a.addActionListener(mouselistener); }
这样,我们在点击按钮时,就会执行mouselistener类中的actionPerformed()方法了
然后,我们给centerjPanel添加MouseListener监听器
centerjPanel.addMouseListener(mouselistener);
这样,我们在centerjPanel用鼠标进行操作的时候就能触发对应的方法了
但是,想要在mouselistener类中达到在centerjPanel绘画,我们还需要将centerjPanel的画笔传递给mouselistener
在mouselistener类中创建画笔和对应的set方法
private Graphics gr = null; public void setGr(Graphics gr) { this.gr = gr; }
在UI类中
//从中间窗体获取画笔 Graphics g = centerjPanel.getGraphics(); //将画笔传递给鼠标监听器 mouselistener.setGr(g);
给centerjPanel添加对应监听器
centerjPanel.addMouseMotionListener(mouselistener); centerjPanel.addMouseListener(mouselistener);
现在,基础知识完备,我们可以来发挥我们的聪明才智,丰富我们的画板了!
6.绘制直线
当我们点击按钮“直线”时,获取按钮的名字
private String firstname = ""; @Override public void actionPerformed(ActionEvent e) { //点击按钮 firstname = e.getActionCommand();//获取按钮的名字 }
然后在按下按钮时,获取x1,y1,松开时,获取x2,y2,绘制
@Override public void mousePressed(MouseEvent e) { //按下 if(name.equals("直线")){ x1 = e.getX(); y1 = e.getY(); } } @Override public void mouseReleased(MouseEvent e) { //释放 if(name.equals("直线")){ x2 = e.getX(); y2 = e.getY(); gr.drawLine(x1,y1,x2,y2); } }
这样,我们在按下“直线”按钮后,在centerJpanel中我们就可以自由的画直线了
然后,就是写绘制三角形和任意多边形的方法了
7.绘制三角形和任意多边形
三角形:
private int flag = 0;
@Override public void mousePressed(MouseEvent e) { //按下 if(name.equals("三角形") && flag == 0){ x1 = e.getX(); y1 = e.getY(); } }
@Override public void mouseReleased(MouseEvent e) { //释放 if(name.equals("三角形") && flag == 0){ x2 = e.getX(); y2 = e.getY(); gr.drawLine(x1,y1,x2,y2); flag++; } }
@Override public void mouseClicked(MouseEvent e) { //点击 if(name.equals("三角形") && flag == 1){ x3 = e.getX(); y3 = e.getY(); gr.drawLine(x1,y1,x3,y3); gr.drawLine(x2,y2,x3,y3); Myshape myshape = new Myshape(x1,y1,x2,y2,x3,y3,name, gr.getColor(),D); myshapes[index++] = myshape; flag--; } }
任意多边形:
@Override public void mouseClicked(MouseEvent e) { //点击 if(name.equals("任意多边形")){ if(e.getButton() == 1){ if(flag == 0) { x1 = e.getX(); y1 = e.getY(); }else if(flag == 1){ x2 = e.getX(); y2 = e.getY(); gr.drawLine(x2,y2,x1,y1); }else { gr.drawLine(x2,y2,e.getX(),e.getY()) x2 = e.getX(); y2 = e.getY(); } flag++; } if(e.getButton() == 3){ gr.drawLine(x2,y2,x1,y1); flag = 0; } } }
8.绘制曲线
在按下方法中
if(name.equals("曲线")){ x1 = e.getX(); y1 = e.getY(); }
@Override public void mouseDragged(MouseEvent e) { //鼠标拖动事件 if(name.equals("曲线")){ x2 = e.getX(); y2 = e.getY(); gr.drawLine(x1,y1,x2,y2); x1 = x2; y1 = y2; } }
9.添加颜色按钮
在学会了如何绘制各种基础图形之后,我们尝试给这些图形添加一些属性
在UI界面中,和添加按钮一样,创建集合存储按钮
//添加右侧颜色按钮 ArrayList<Color> colorlist = new ArrayList<>(); colorlist.add(Color.yellow); colorlist.add(Color.pink); colorlist.add(Color.black); colorlist.add(Color.blue); colorlist.add(Color.red); colorlist.add(Color.cyan); colorlist.add(Color.DARK_GRAY); colorlist.add(Color.GRAY); colorlist.add(Color.GREEN); colorlist.add(Color.LIGHT_GRAY); colorlist.add(Color.MAGENTA); colorlist.add(Color.ORANGE); colorlist.add(Color.WHITE); for(Color color : colorlist){ JButton a = new JButton(); a.setPreferredSize(new Dimension(30,30));//设置按钮大小 a.setBackground(color); eastjPanel.add(a); a.addActionListener(mouselistener); }
然后在mouslistener类的actionPerformed()方法中
private String firstname = "",name = "";
@Override public void actionPerformed(ActionEvent e) { //点击按钮 firstname = e.getActionCommand(); if(firstname == ""){ JButton JButton = (JButton) e.getSource();//e.getSource():获取按钮对应的对象(Object类) gr.setColor(JButton.getBackground()); }else{ name = firsename; } }
这样,我们就获得了这样的界面
10.自定义颜色
众所周知,所有颜色都是由绿色,红色,蓝色三种基础色进行混合合成的,所以,我们也可以给我们的画板添加自定义颜色
在UI类中
//自定义颜色 JTextField R = new JTextField(3); JTextField G = new JTextField(3); JTextField B = new JTextField(3); R.setText("0"); G.setText("0"); B.setText("0"); southjPanel.add(new JLabel("自定义颜色 R:")); southjPanel.add(R); southjPanel.add(new JLabel("G:")); southjPanel.add(G); southjPanel.add(new JLabel("B:")); southjPanel.add(B); JButton a1 = new JButton("确定"); southjPanel.add(a1); a1.addActionListener(mouselistener);
效果
在mouselistener类中
private JTextField R; private JTextField G; private JTextField B;
@Override public void actionPerformed(ActionEvent e) { //点击按钮 firstname = e.getActionCommand(); if(firstname == "确定"){ gr.setColor(new Color(Integer.parseInt(R.getText()),Integer.parseInt(G.getText()),Integer.parseInt(B.getText()))); }else if(firstname == ""){ JButton JButton = (JButton) e.getSource();//e.getSource():获取按钮对应的对象(Object类) gr.setColor(JButton.getBackground()); }else{ name = firsename; } }
11.设置粗细
//添加底侧按钮和文本框 ArrayList<String> downlist = new ArrayList(); downlist.add("加粗"); downlist.add("减细");
在mouselistener类中,设置静态变量D表示粗细
static int D = 3;
@Override public void actionPerformed(ActionEvent e) { //点击按钮 Graphics2D d2 = (Graphics2D)gr; gr = d2; d2.setStroke(new BasicStroke(D));//Graphics2D类有设置粗细的方法 firstname = e.getActionCommand(); if(firstname == "确定"){ gr.setColor(new Color(Integer.parseInt(R.getText()),Integer.parseInt(G.getText()),Integer.parseInt(B.getText()))); }else if(firstname == ""){ JButton JButton = (JButton) e.getSource();//e.getSource():获取按钮对应的对象(Object类) gr.setColor(JButton.getBackground()); }else if(firstname == "加粗"){ D += 2; }else if(firstname == "减细"){ if(D > 1){ D -= 2; }else{ name = firsename; } }
现在,效果图就是这样了
12.重写paint()方法
要注意,Jfream在窗体发生任意改变的时候,都会重新调用panit()方法,所以在我们绘制了一些图形之后,一旦我们对窗体进行了任意改动,比如把窗口拉大,移动窗口到屏幕外,都会使得我们辛辛苦苦画的图形消失或者残缺,所以为了不让这种状况发生,我新建了Myshape类用于存储我们画的物体的数据,并且在paint()时调用。
由于我们是要重绘centrjPanel面板,所以让UI继承JPanel
将UI界面中的centrjPanel.改为this.
借鉴传递画笔的过程,将UI对象传递给mouslistener类
mouselistener.setUi(this);//UI
private UI ui = null; public void setUi(UI ui) { this.ui = ui; }//mouslistener
public class Myshape { private int x1; private int y1; private int x2; private int y2; private int x3; private int y3; private String name; private Color color; private int D;//粗细 //初始化属性 public Myshape(int x1, int y1, int x2, int y2, String name, Color color, int d) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.name = name; this.color = color; D = d; } public Myshape(int x1, int y1, int x2, int y2, int x3, int y3, String name, Color color, int d, int fengxingFlag) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.x3 = x3; this.y3 = y3; this.name = name; this.color = color; D = d; this.fengxingFlag = fengxingFlag; } public Myshape(int x1, int y1, int x2, int y2, int x3, int y3, String name, Color color, int d) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.x3 = x3; this.y3 = y3; this.name = name; this.color = color; D = d; } //还原图形 public String getName() { return name; } public void drawShape(Graphics g){ Graphics2D d2 = (Graphics2D)g; g.setColor(color); d2.setStroke(new BasicStroke(D)); switch (name){ case "直线": g.drawLine(x1,y1,x2,y2); break; case"三角形": g.drawLine(x1,y1,x2,y2); g.drawLine(x1,y1,x3,y3); g.drawLine(x3,y3,x2,y2); break; case "曲线": g.drawLine(x1,y1,x2,y2); break; case "任意多边形": g.drawLine(x1,y1,x2,y2); break; } } }
在UI界面中重写paint方法
@Override public void paint(Graphics g){ super.paint(g); for (int i = 0; i < myshapes.length; i++) { if (myshapes[i] != null) { myshapes[i].drawShape(g); // System.out.println(myshapes[i].getName()); } } }
然后在mouselistener类中创建myshapes数组
private Myshape[] myshapes = new Myshape[10000]; private int index = 0;
然后在需要存储的地方,用对应的构造器进行存储,例如:
Myshape myshape = new Myshape(x1,y1,x2,y2,x3,y3,name, gr.getColor(),D); myshapes[index++] = myshape;
13.清空方法
给界面添加清空按钮
functionlist.add("清空");
if(firstname == "清空"){ ui.flag = true; ui.rep(); }
public void rep(){ paint(this.getGraphics()); for (int i = 0; i < myshapes.length; i++) { myshapes[i] = null; } }