图板优化
上次做的简单画图板过程很麻烦,重复的代码也很多,而且更让我们受不了的是bug太多啦,你会发现当窗体被拉伸的时候,图消失了!并且多拖出来的面板部分不能使用左边面板按钮效果。相对于真正的画图板,我们也发现画图形时效果也没显示出来,那我们该怎么解决这两个大问题呢~其实方法非常简单~今天我们学习的内容首先是分工合作(封装)~然后再来优化我们的画图板吧!
一.主要内容
- 封装(窗体框架、左面板、中间面板、底部面板、测试函数)
- 画板的重绘
2.1 泛型(MyList)列表
2.2 Shape(父类)与各形状子类(ShapeLine、ShapeOval、ShapeRect、ShapeRound_Rect……) - 显示效果
二.封装(Frame、pLeft、pCenter、pBottom、Test)
1.Frame类
//继承JFrame属性
public class Frame extends JFrame {
//需要的属性
public pLeft pLeft;
pBottom pBottom = null;
pCenter pCenter = null;
Graphics2D graphicsLeft;
//设置窗体属性,并添加组件
public void setFrame() {
this.setSize(500, 500);
this.setLocationRelativeTo(null);
this.setTitle("画图板");
this.setDefaultCloseOperation(3);
this.setLayout(new BorderLayout());
pBottom = new pBottom();
pBottom.setBottomPanel();
pCenter = new pCenter();
pLeft = new pLeft(graphicsLeft, pBottom);
this.add(pCenter, BorderLayout.CENTER);
this.add(pLeft, BorderLayout.WEST);
this.add(pBottom, BorderLayout.SOUTH);
this.setVisible(true);
//画笔必须在 setVisible(true);之后!传画笔!
graphicsLeft = (Graphics2D) pCenter.getGraphics();
pLeft.g = graphicsLeft;
pCenter.g = graphicsLeft;
pBottom.g = graphicsLeft;
//将左边面板传给中间面板,中间面板会用到
pCenter.pL = pLeft;
}
}
2.左边画板(pLeft)
//继承JPanel
public class pLeft extends JPanel {}
//需要的属性
public int pressedCount;// 多边形按下的次数 int pressedCount=0
public String currentComman = "line"; // 默认一开始就是直线
public Color currentColor = Color.black;//默认一开始就是黑色
public Graphics2D g;// 此时g=null;
pBottom pBottom;// 表示pBottom=null;
public int count;
// 构造方法
public pLeft(Graphics2D gr, pBottom p) {
this.g = gr;
this.pBottom = p;
Dimension dSizie = new Dimension(70, 100);
this.setPreferredSize(dSizie);// 设置窗体大小
this.setBackground(Color.gray);// 设置背景颜色
// 添加JButton添加图片
String[] value = { "star", "airbrush", "brush", "color_picker","curve", "dot_rect", "eraser", "fill", "line", "magnifier","oval", "pencil", "polygon", "rect", "round_rect", "word" };
ActionListener actionlistener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
//获得当前触发按钮的命令
currentComman = e.getActionCommand();
count = 0;
}
};
for (int i = 0; i < 16; i++) {
ImageIcon imageicon = new ImageIcon("images/" + value[i] + ".jpg");
JButton button = new JButton(imageicon);
Dimension preferredSize = new Dimension(25, 25);
button.setPreferredSize(preferredSize);
// 给按钮添加监听
button.addActionListener(actionlistener);
// 给触发按钮设置一个命令
button.setActionCommand(value[i]);
this.add(button);
}
}
3.中间面板(pCenter)
//继承Jpanel
public class pCenter extends JPanel {}
//需要的属性
public int xStart1;
public int yStart1;
public int xClick1;
public int yClick1;
public int xEnd1;
public int yEnd1;
public int clickcount;
public int yClick2;
public int xClick2;
public int xStart;
public int yStart;
public int xEnd;
public int yEnd;
public int count;
public Graphics2D g;
pLeft pL;// = null;
Random random = new Random();// 随机数生成器
Shape shape = null;
//构造函数
public pCenter() {
this.setBackground(Color.white);// 设置背景颜色
MouseListener mouse = new MouseListener() {
public void mouseClicked(MouseEvent e) {
System.out.println("点击了");
//多边形
if ("polygon".equals(pL.currentComman)) {
clickcount = e.getClickCount();
if (clickcount == 1) {
xClick1 = e.getX();
yClick1 = e.getY();
g.drawLine(xClick1, yClick1, xEnd1, yEnd1);
myList.add(new ShapeLine(xClick1, yClick1, xEnd1,yEnd1, g.getColor(), 1));
xEnd1 = xClick1;
yEnd1 = yClick1;
} else if (clickcount == 2) {
xClick2 = e.getX();
yClick2 = e.getY();
g.drawLine(xEnd1, yEnd1, xStart1, yStart1);
//放到容器中重绘
myList.add(new ShapeLine(xEnd1, yEnd1, xStart1,yStart1, g.getColor(), 1));
count = 0;
}
}
}
public void mouseEntered(MouseEvent e) {
System.out.println("进入了");
}
public void mouseExited(MouseEvent e) {
System.out.println("退出了");
}
public void mousePressed(MouseEvent e) {
System.out.println("按下了");
xStart = e.getX();
yStart = e.getY();
g.setColor(Color.BLACK);
Stroke stroke = new BasicStroke(1);
g.setStroke(stroke);
}
public void mouseReleased(MouseEvent e) {
System.out.println("释放了");
xEnd = e.getX();
yEnd = e.getY();
// 画
if ("line".equals(pL.currentComman))
{g.drawLine(xStart, yStart, xEnd, yEnd);}
else if ("polygon".equals(pL.currentComman)) {
if (count == 0) {
xStart1 = xStart;
yStart1 = yStart;
g.drawLine(xStart, yStart, xEnd, yEnd); xEnd1 = e.getX();
yEnd1 = e.getY();
count++;
}
}
}
};
MouseMotionListener mouseMotionLisener = new MouseMotionListener() {
public void mouseDragged(MouseEvent e) {
int x1 = e.getX();
int y1 = e.getY();
if ("pencil".equals(pL.currentComman))
{ g.drawLine(xStart, yStart, x1, y1);
xStart = x1;yStart = y1;
} else if ("airbrush".equals(pL.currentComman)) {for (int i = 0; i < 25; i++) {
int nextInt1 = random.nextInt(8) - 4;
int nextInt2 = random.nextInt(8) - 4;
g.drawLine(x1 + nextInt1, y1 + nextInt2, x1 + nextInt1,y1 + nextInt2); }}if ("eraser".equals(pL.currentComman)) {
g.setColor(Color.WHITE);
BasicStroke stroke = new BasicStroke(10);
((Graphics2D) g).setStroke(stroke);
g.drawLine(xStart, yStart, x1, y1);
xStart = x1;
yStart = y1;
}
if ("brush".equals(pL.currentComman)) {
Stroke stroke = new BasicStroke(10);
g.setStroke(stroke);
g.drawLine(xStart, yStart, x1, y1);
xStart = x1;
yStart = y1;
}
}
public void mouseMoved(MouseEvent e) {
}
};
this.addMouseMotionListener(mouseMotionLisener);
this.addMouseListener(mouse);
}
}
4.底部面板.pBottom
public class pBottom extends JPanel {
public Color[] colors = { Color.BLACK, Color.BLUE, Color.GREEN,
Color.ORANGE, Color.YELLOW, Color.LIGHT_GRAY, Color.PINK,
Color.CYAN, Color.WHITE };
pLeft pLeft;
public Graphics2D g;
public Color currentColor;
public void setBottomPanel() {
Dimension d = new Dimension(100, 50);
this.setPreferredSize(d);
// 创建按钮的点击事件
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
//获取当前命令
String command = e.getActionCommand();
int i = Integer.valueOf(command);
Color color = colors[i];
g.setColor(color);
currentColor = color;
}
};
for (int i = 0; i < 9; i++) {
JButton button = new JButton();
button.setBackground(colors[i]);
Dimension dd = new Dimension(25, 25);
button.setPreferredSize(dd);
button.addActionListener(listener);
button.setActionCommand(i + "");
// 添加
this.add(button);
}
}
}
5.测试函数
public class Test {
public static void main(String[] args) {
Frame p = new Frame();
p.setFrame();
}
}
三、画板的重绘
1.泛型
1.1泛型,即“参数化类型”。顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。在泛型接口、泛型类和泛型方法的定义过程中,我们常见的如T、E、K、V等形式的参数常用于表示泛型形参。
1.2自定义泛型
public class MyList<T> {
private int size = 0;
private Object[] ages = new Object[size];
public int getsize() {
return size;
}
public T get(int i) {
return (T) ages[i];
}
public boolean add(T age) {
Object[] ages_new = new Object[size + 1];
for (int i = 0; i < size; i++) {
ages_new[i] = ages[i];
}
ages_new[size] = age;
size++;
ages = ages_new;
return true;
}
public boolean delete(int index) {
Object[] ages_new = new Object[size - 1];
for (int i = 0; i < index; i++) {
ages_new[i] = ages[i];
}
for (int i = index + 1; i < size; i++) {
ages_new[i] = ages[i];
}
// 从0开始
ages = ages_new;
size--;
return true;
}
public int check(int index) {
return (int) ages[index];
}
public void update(int index, T age) {
ages[index] = age;
}
}
2.Shape抽象类
2.1抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
2.2抽象类不能用来创建对象;
2.3如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。
2.4
public abstract class Shape {
public int x1, y1, x2, y2;
public Color currentcolor;
public int stroke = 1;
public Shape(int x1, int y1, int x2, int y2, Color currentcolor, int stroke) {
super();
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.currentcolor = currentcolor;
this.stroke = stroke;
}
public String toString() {
return "Shape [x1=" + x1 + ", y1=" + y1 + ", x2=" + x2 + ", y2=" + y2
+ ", currentcolor=" + currentcolor + ", stroke=" + stroke + "]";
}
public abstract void paint(Graphics2D g);
}
2.5实例ShapeLine类(其他类似)
public class ShapeLine extends Shape {
public ShapeLine(int x1, int y1, int x2, int y2, Color currentcolor,
int stroke) {
super(x1, y1, x2, y2, currentcolor, stroke);
}
public void paint(Graphics2D g) {
g.setColor(currentcolor);
g.setStroke(new BasicStroke(stroke));
g.drawLine(x1, y1, x2, y2);
}
}
2.6在中间面板将图形的绘制添加到列表,并重绘出来。
//g.drawLine(xStart, yStart, xEnd, yEnd);
myList.add(new ShapeLine(xStart, yStart, xEnd, yEnd, g
.getColor(), 1));
2.7其他图形和多边形也是相同情况,重绘多边形时每一步都用ShapeLine重绘出来。
2.8中间面板
将MyList列表中存储的图形全部重绘出来
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < myList.getsize(); i++) {
myList.get(i).paint((Graphics2D) g);
}
}
2.9每次添加到容器中,都用repaint();刷新
四、显示效果
1.如绘制直线时显示效果,则应在鼠标拖动时就画出来,为避免画一坨的情况,应该增加一个中间变量来记录。
Shape shape = null;
鼠标拖动时
if ("line".equals(pL.currentComman)) {
shape = new ShapeLine(xStart, yStart, x1, y1, g.getColor(),1);}
中间面板重绘时
if (shape != null) {
shape.paint((Graphics2D) g);
}