JAVA中Swing的绘制原理以及如何实现动态图画

首先先吐槽一下用JAVA做界面的辛苦,往面板里绘制东西要获取他的Graphics,可往往要往里面画的类是别的类,然后你往里面画的时候…..坑就出来了。

Swing组件绘制的原理

组件在初始画的时候会调用组件本身自带的paint()和paintComponent(),绘制出他想要的样子,如果你单纯想改变他的形状和样子时,就可以重写paint()或者paintComponent来达成。不过要注意,在Swing的原始组件中的paint()会调用paintComponent(),假如你想在paint()里绘制某个图像,paintComponent中绘制另一个()并且不想两个图像混在一起。看下列实例

以JPanel为例

public class MyPanel extends JPanel{
    @Override
    protected void paintComponent (Graphics g) {
        super.paintComponent(g);
        System.out.println("component");
    }

    @Override
    public void paint (Graphics g) {
        super.paint(g);
        System.out.println("paint");
    }

    public static void main(String [] ars){
        JFrame frame = new JFrame("paintTest");
        MyPanel panel = new MyPanel();
        frame.add(panel);
        frame.setSize(300,300);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.setVisible(true);
    }
    class MyButton()
}
运行结果是:
component
paint

如果不想调用paintComponent(),可以将super.paint()注释掉,这对于Jpanel来说是没有什么问题的,但对于其他组件,例如JButton来说,JButton就不可正常显示了。

    public class MyButton extends JButton {
    public MyButton (String string) {
        super(string);
    }

    @Override
    protected void paintComponent (Graphics g) {
        super.paintComponent(g);
    }

    @Override
    public void paint (Graphics g) {
       // super.paint(g);
    }
}
    MyButton button = new MyButton("button");
       frame.add(button,BorderLayout.EAST);

图片插入不了,自己脑补吧。
所以可以自己根据实际情况来将自己要写的函数写在paint()或者paintComponent()

repaint()的实质其实是调用paint()重新绘制组件

timer.schedule(new TimerTask() {
            @Override
            public void run ( ) {
                panel.repaint();
            }
        },1000);

这里要注意,如果你在调用了paint()同一个线程里调用repaint(),他不会重新绘制,因为paint()会查看你是否已经绘制了该组件,如果绘制了就不可重新绘制。所以在这里我们新建一个线程来执行重新绘制。同理,在已经绘制组件后获取组件的Graphics进行绘图也不会有任何显示。
例如

    public static void main(String [] ars){
        JFrame frame = new JFrame("paintTest");
        MyPanel panel = new MyPanel();
        frame.add(panel);
        frame.setSize(400,400);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        /*panel.repaint();这样不会panel不会重新绘制*/
        /*或者
        Graphics graphics = panel.getGraphics();
        graphics.drawLine(0,0,50,50) 这样也不会有任何作用
        */
    }

源码里的调用时这样的,具体逻辑可在JDK里看。

    boolean printing = getFlag(IS_PRINTING);  
结果是
component
paint
component
paint

动态图画的绘制

下面举出一个实例来实现动态图画

public class MyPanel extends JPanel{
    int x =50;
    int y =50;
    @Override
    public void paint (Graphics g) {
        super.paint(g);
        g.setColor(Color.red);
        g.fillOval(x,y,30,30);
    }
    public static void main(String [] ars){
        JFrame frame = new JFrame("paintTest");
        MyPanel panel = new MyPanel();
        frame.add(panel);
        frame.setSize(400,400);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        panel.repaint();
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run ( ) {
                if(panel.x<=300){
                    panel.x++;
                    panel.repaint();
                }
            }
        },0,20);
    }
}

Timer的主要用处在于创建一个新的线程,也可以用监听器代替。
注意不要写成这样,这样图画会闪烁不连续,具体为什么我也不太清楚了,可能是Swing画图时的会自己创建线程,导致抢资源了。

timer.schedule(new TimerTask() {
            Graphics graphics = panel.getGraphics();
            @Override
            public void run ( ) {
                if(panel.x<=300){
                    graphics.setColor(Color.red);
                    graphics.fillOval(panel.x,panel.y,30,30);
                    panel.x++;
                    panel.repaint();
                }
            }
        },0,10);

你可能感兴趣的:(java,swing)