如何成功绘制背景JPanel一次并不断更新前台JPanel?

时间:2016-07-25 15:51:00

标签: java swing graphics graphics2d

我有一个自定义的JLayeredPane,我在游戏循环中重新绘制它。 JLayeredPane中添加了两个自定义JPanel。这些是前景和后台JPanel。我如何成功只绘制我的背景JPanel一次,(并重新调整窗口大小或任何其他原因)以减少对系统资源的影响,同时继续不断更新我的前台JPanel。

要重新迭代,我不想在循环中不断重绘背景JPanel。我只想在它是必要的时候重新绘制它,因为背景不会改变。而且很大。

在我尝试这样做时,我只画了一次背景。然而。背景JPanel根本不可见。而前台JPanel正常更新。这几乎就像前景JPanel在背景JPanel上绘制一样,即使我将两个JPanel都设置为setOpaque(false)

我制作了一个mvce,显示我只尝试绘制背景JPanel一次,同时不断更新前景JPanel。

我的代码的问题是后台JPanel没有显示。

现在。我知道,如果我不断画它会显示出来。但这违背了我想要做的目的。我试图只绘制一次,并且同时被看到

我的代码成功只绘制了一次背景JPanel。问题是背景JPanel没有显示。我该如何解决这个问题

import javax.swing.*;

import java.awt.*;
import java.awt.event.*;

public class Main extends JLayeredPane {
    static JFrame frame;
    static Main main;
    static Dimension screenSize;
    public Main() {     
        JPanel backPanel = new BackPanel();
        JPanel frontPanel = new FrontPanel();
        add(backPanel, new Integer(7));
        add(frontPanel, new Integer(8));

        new Thread(() -> {
            while (true){
                repaint();
            }
        }).start();

    }

    public static void main(String[] args) {
        screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        frame = new JFrame("Game"); // Just use the constructor

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        main = new Main();
        frame.add(main, BorderLayout.CENTER);

        frame.pack();
        frame.setSize(screenSize);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }
    public class BackPanel extends JPanel{
        public boolean drawn = false;
        public BackPanel(){
            setVisible(true);
            setOpaque(false);
            setSize(screenSize);
            JLabel test1 = new JLabel("Test1");
            JLabel test2 = new JLabel("Test2");
            add(test1);
            add(test2);
        }
        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            drawOnce(g);
        }
        public void drawOnce(Graphics g){
            if (!drawn){
                g.setColor(Color.red);
                g.fillRect(0, 0, screenSize.width, 200);
                drawn=true;
            }

        }
    }
    public class FrontPanel extends JPanel{

        public FrontPanel(){
            setVisible(true);
            setOpaque(false);
            setSize(screenSize);
            JLabel test = new JLabel("Test");
            add(test);
        }
        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            g.setColor(Color.blue);
            g.fillRect(0+screenSize.width/2, 0, screenSize.width/4, 300);
        }
    }
}

2 个答案:

答案 0 :(得分:0)

尝试RepaintManager.currentManager(组件).markCompletelyClean(组件)。它会阻止组件重新绘制。每次添加新组件后,您可能需要执行此操作。

http://docs.oracle.com/javase/6/docs/api/javax/swing/RepaintManager.html#markCompletelyClean%28javax.swing.JComponent%29

答案 1 :(得分:0)

我不知道这两行代码是否

super.paintComponent(g);
drawOnce(g);

是问题的根源,我真的不记得paintComponent是如何工作的(测试可以帮助)但是尝试交换它们:

drawOnce(g);
super.paintComponent(g);

也许,在您的原始版本中,您告诉JVM绘制整个组件,并且只有在将AWTEvent添加到队列之后,才能绘制您需要的内容。 我想awt的文档会解释它。