目录
1.绘图原理:
Component类提供了两个和绘图相关的最重要的方法:
1.paint(Gaphics g)绘制组件的外观
2.repaint()刷新组件的外观
2.paint()
这个方法是JComponent类底下的一个方法,
/**
*由Swing调用以绘制组件。应用程序不应该直接调用paint,而应该使用repaint方法来调度组件进行重
*绘。
*这个方法实际上将绘制工作委托给三个受保护的方法:paintComponent、paintBorder和*paintChildren。
*按照列出的顺序调用它们,以确保子组件出现在组件本身的顶部。一般来说,组件及其子组件不应该在分
*配
*给边框的insets区域内绘制。子类可以像往常一样重写这个方法。想要专门化UI(外观和感觉)委托的*paint
*方法的子类应该只重写paintComponent。
*形参:
*g -要在其中绘制的图形上下文
*
* @param g the <code>Graphics</code> context in which to paint
* @see #paintComponent
* @see #paintBorder
* @see #paintChildren
* @see #getComponentGraphics
* @see #repaint
*/
public void paint(Graphics g){...}
我们可以从官方的注释里面看到,对于paint()方法的调用我们一般不是直接调用,而是自定义一个类去继承他所在的类然后进行重写,再由repaint进行调用。这里说的有点笼统,我们来看例子:
这里我们先定义一个MyPanel的类:
class MyPanel extends JPanel{
@Override
public void paint(Graphics g) {//绘图方法
super.paint(g);//调用父类的方法完成初始化
System.out.println("paint 方法被调用");
//画一个圆
g.drawOval(10,10,100,100);
}
}
但这里有个问题,paint不是JComponnet类的方法吗,但这里却继承了JPanel。JPanel他继承了JComponent类,并且继承了Accessible的接口,如下:
public class JPanel extends JComponent implements Accessible
但如果我们直接去继承JComponnet类可以吗,是可以的,如下:
class MyPanel extends JComponent{
@Override
public void paint(Graphics g) {//绘图方法
super.paint(g);//调用父类的方法完成初始化
System.out.println("paint 方法被调用");
//画一个圆
g.drawOval(10,10,100,100);
}
}
单纯对于再画板上面画图是可以的,但可能在后期会出现很多的问题。所以我们还是用JPanel来写。在定义完了我们的类以后我们来看重写paint方法里面的函数体。
super.paint(g);//调用父类的方法完成初始化
//画一个圆
g.drawOval(10,10,100,100);
里面其实就这两个语句,第一句很好理解,就是用之前的父类paint方法完成初始化 这里并不陌生,因为在java里面,对于重写方法来说,除非你想完全推翻父类的方法,一般来说都会,在这里调用父类的方法并在后面加上一些。但你得注意加上super,不能直接写paint那样就是直接调用自己了,那并没有什么用。然后就是Grphics类的drawOval方法了
/**
* Draws the outline of an oval.
* The result is a circle or ellipse that fits within the
* rectangle specified by the {@code x}, {@code y},
* {@code width}, and {@code height} arguments.
* <p>
* The oval covers an area that is
* <code>width + 1</code> pixels wide
* and <code>height + 1</code> pixels tall.
* @param x the <i>x</i> coordinate of the upper left
* corner of the oval to be drawn.
* @param y the <i>y</i> coordinate of the upper left
* corner of the oval to be drawn.
* @param width the width of the oval to be drawn.
* @param height the height of the oval to be drawn.
* @see java.awt.Graphics#fillOval
*/
public abstract void drawOval(int x, int y, int width, int height);
其实对于Grphics类,他是一个抽象类。而drawOval是一个抽象方法,对于他的参数来说,x,y是这个你画的圆的离边界x,y轴的距离,weight和height是圆的高和宽。这里注意,这个函数是专门用来画圆的,但也可以是椭圆,只要改变width和height的比例即可
这两个地方,并且这里的参数单位是像素。在这里大家不要把像素和厘米搞混了,虽然我们经常会说几个像素,但其实像素是密度单位,而厘米是长度单位。
然后我们来看,怎么实现这个类:
首先我们定义一个public类和我们平时写java的代码一样,要留有main()方法:
public class Draw_Circle extends JFrame{
private MyPanel mp=null;
public static void main(String[] args) {
new Draw_Circle();
}
public Draw_Circle(){
//初始化面板
mp=new MyPanel();
//把面板放入到框架里面去
this.add(mp);
//设置窗口的大小
this.setSize(400,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//点击窗口的小叉,程序就完全退出
this.setVisible(true);//可以显示
}
}
但这里和平时不同的是,我们这里继承了一个JFrame类,这里的JFrame类是一个框架,所以我们这里理解起来就不要从底层代码来理解他这样会增加我们理解的难度。这里对与JFame来说我们可以把他理解成一个画框,我们要做的事情就是要把我们的画板嵌入到这个画框里面去。而我们的画板就是刚刚我们定义的MyPanel类,但是我们平时写代码并不会写公开类的构造函数(当然,这有可能是因为我之前写的代码比较简单),但这里为了把画板嵌入到框架里面去,我这里先定义了一个类对象指向画板,让通过this.add()把画板嵌入,然后用setSize()定义画框的大小,然后用setVisble(true)让内容可视化。结果如下:
但这个时候你会发现一个问题,那就是如果你去点右上角的小叉,你会发现你无法停止代码运行,所以这里我们就使用一个语句:
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
这样你在关上窗口的同时也可以完成停止程序的运行。
但其实这里我们写了这么多,你会发现一个问题,我们只是构建了一个MyPanel对象,并没有去调用我们的paint方法。首先我们要知道,paint方法的作用是用来绘制组件的外观。这里就要聊到paint()方法是在Container类中,在容器也就是组件被改变的时候。我们会先调用repaint()方法,然后调用update(Graphics g),最后调用paint()方法去绘制组件。所以我们发现每次当需要我们重新绘制组件的时候我们就需要调用paint()方法,这个地方在后面的repaint()方法会详细讲。所以存在以下三种情况会调用paint方法:
1.在组件第一次显示的时候
2.窗口最大化再最小化的时候
3.窗口大小被改变的时候