包java.awt
中有一个类,叫做Graphics
。这个类有很多可以在组件(java.awt.Component
类及它的子类)上绘制图形的方法。这个类在功能上像画笔。
所有组件(Component
)类都有一个方法,叫做getGraphics()
。如果一个组件已经显示(setVisible(true)
),getGraphics()
会返回一个与该组件对应的Graphics
对象;否则返回null
。
包java.awt.event
中有一些监听器。MouseMotionListener
可以监听鼠标拖动(drag,按下鼠标主键同时拖动)时的坐标。MouseListener
可以监听鼠标的按下、点击、释放时的坐标。
Graphics
类中的方法下面是 Graphics
类中常用的绘图方法。参数列表中的坐标的坐标原点,在Graphics
对象所对应的组件中。横、纵轴的正方向分别是右、下。
返回值类型 | 方法名 和 参数列表 | 描述 |
---|---|---|
void | drawLine (int x1, int y1, int x2, int y2) | 在点 (x1, y1) 和 (x2, y2) 之间画一条线。 |
void | drawOval (int x, int y, int width, int height) | 绘制椭圆的轮廓。 |
void | drawRect (int x, int y, int width, int height) | 绘制矩形的轮廓。 |
void | drawString (String str, int x, int y) | 绘制由指定 string 给定的文本。 |
Graphics
类中还有 setColor()
getColor()
setFont()
getFont()
四个方法,可以更改、获取画笔的颜色和字体。
这有什么难的咯
曲线可以看成是许多段极短的直线段首尾相接连成的。可以在鼠标拖动时,连续不停地记录鼠标的坐标、并画出连续的直线段。
class Listener implements MouseListener, MouseMotionListener {
private int x1, x2, y1, y2;
private Graphics graphics;
//...
public void mouseDragged(MouseEvent e) {
x2 = e.getX(), y2 = e.getY();
graphics.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
}
}
擦除图像就是在指定的位置画出线条的过程。只不过线条的颜色是背景色。所以要先设定画板背景色,因为默认的背景色不是白色。
Graphics 默认的笔触很小。可以用下面的代码增大 Graphics 的笔触。
int size;
//...
Graphics2D g = (Graphics2D) graphics;
g.setStoke(new BasicStoke(size)); // size 是表示笔触大小的整数。原来为 1
在调用 drawOval() 和 drawRect() 时,要把图形的左上角的坐标作为参数。但是我们不知道用户会不会按↙和↗方向来拖动鼠标,所以我们要先处理坐标。
private int min(int a, int b) {
return a < b ? a : b;
}
private int abs(int a) {
return a < 0 ? -a : a;
}
//...
drawOval(min(x1, x2), min(y1, y2), abs(x1 - x2), abs(y1 - y2));
用setColor()
方法即可。
可以在界面上创建多个按钮,更改它们的背景色。同时,让按钮的监听器记录按钮的背景色即可。
Color color;
//...
public void actionPerformed(ActionEvent e) {
color = ((JButton) e.getObject()).getBackground();
}
我们希望,我们在拖动鼠标的时候就能即时看到图形的效果,还希望图形的预览效果是随着鼠标的拖动实时变化的。
然而现在的画板只有在释放鼠标之后才会显示图形。没有预览效果,我们就不知道图形有没有画歪。
一个很朴素的想法是, 在拖动的时候就把图形画出来。每当鼠标坐标改变,就用背景色擦除上一次画出的预览效果,然后再画一次新的预览效果。
不难想到,拖动鼠标时,画板上会多出很多白色的线。这些白色的线可能会遮挡原先画好的图形。
另一个很朴素的想法是,把先前已经画好的图形全部记录下来。每一次画出白线之后,就把之前记录的图形重新画出来。
Java 没有现成的类来记录这些图形。所以要自己定义一个类。
class Shape {
int x1, y1, x2, y2, color, type; // type 记录图形的种类
// 下面写构造方法,这里略去。
}
然后我们就可以用这个类的对象的数组来记录图形了。
paint()
方法在 Java 中,能够显示出来的组件,都是由 Graphics
类的对象来绘制出来的。当我们让一个组件或者使一个最小化/被遮挡的组件变为可见时,它的 paint()
方法会被调用,这个方法会重新绘制组件。
返回值类型 | 方法名 和 参数列表 | 描述 | 访问权限 |
---|---|---|---|
void | paint (Graphics g) | 用g 重新绘制组件 |
public |
如果画板上原来已经画了图形,我们再点最小化
,然后最大化
,这个窗体上的所有组件都会被重新绘制一遍。重新绘制的组件就会遮挡原有的图形。
为了让被遮挡的图形重新显示,应该重写paint()
方法,让组件在重新绘制之后,把原有的图形也画上去。
class PaintBoard extends JPanel {
//...
public void paint(Graphics g) {
super.paint(g); // 先调用基类的方法,绘制组件。
for(Shape s : arr) { // arr 类型是 Shape[]
paint(s); // 画出图形 这里的 paint() 是自己定义的方法
}
}
}
super
是指代基类的关键字。