简体   繁体   English

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

[英]How to successfully draw background JPanel once and update foreground JPanel constantly?

I have a custom JLayeredPane, and I am repainting it in my game loop. 我有一个自定义的JLayeredPane,并且正在游戏循环中重新粉刷它。 There are two custom JPanels added into the JLayeredPane. 在JLayeredPane中添加了两个自定义JPanel。 These are foreground and background JPanels. 这些是前台和后台的JPanel。 How do I successfully only draw my background JPanel once, (And repaint when window is re-sized or any other reason) to reduce impact on system resources, while continuing to update my foreground JPanel constantly. 如何成功地仅绘制一次我的背景JPanel(并且在调整窗口大小或任何其他原因时重新绘制)以减少对系统资源的影响,同时继续不断更新我的前景JPanel。

To re-iterate, I dont want to constantly repaint the background JPanel in a loop. 重申一下,我不想在循环中不断重绘背景JPanel。 I want to repaint it only when it is nessessary, as the background does not change. 我只想在必要时重涂它,因为背景不会改变。 and is large. 而且很大。

In my attempt to do this, I have only drawn the background once. 在尝试执行此操作时,我仅绘制了一次背景。 However. 然而。 the background JPanel is simply not visible. 后台JPanel根本不可见。 while the foreground JPanel updates as normal. 而前台JPanel则正常更新。 It is almost as if the foreground JPanel paints ontop of the background JPanel, even though I have both of the JPanels set to setOpaque(false) 即使我将两个JPanels都设置为setOpaque(false) ,前景JPanel几乎就像在背景JPanel的顶部绘制一样

I have made a mvce which shows my attempt at only drawing the background JPanel once, while updating the foreground JPanel constantly. 我制作了一个mvce,它显示了我只绘制背景JPanel一次而不断更新前景JPanel的尝试。

The problem with my code is that the background JPanel does not show. 我的代码的问题是后台JPanel无法显示。

Now. 现在。 I know that if I were to draw it constantly it would show. 我知道如果我不断绘制它会显示出来。 But that defeats the purpose of what i'm trying to do. 但这违背了我想要做的目的。 I am trying to only draw it once, and have be seen at the same time 我试图只画一次,并且同时被看到

My code successfully only draws the background JPanel once. 我的代码仅成功绘制了一次后台JPanel。 The problem is that the background JPanel does not show. 问题是背景JPanel不显示。 How do I fix THIS problem 我该如何解决这个问题

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);
        }
    }
}

Try RepaintManager.currentManager(component).markCompletelyClean(component). 尝试RepaintManager.currentManager(component).markCompletelyClean(component)。 It will prevent the component from repainting. 这将防止组件重新粉刷。 You might need to do this after each time you add new components. 每次添加新组件后,您可能需要执行此操作。

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

I don't know if this two lines of code 我不知道这两行代码

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

are the root of problem, I sincerly don't remember how paintComponent works (a test could help) but try to swap them : 是问题的根源,我真诚地不记得paintComponent的工作原理(测试可能会有所帮助),但尝试交换它们:

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

maybe, on your original version, you tells JVM to paint the whole component and, only after the AWTEvent has been added to the queue, to draw what you need. 也许,在您的原始版本上,您告诉JVM绘制整个组件,并且仅在将AWTEvent添加到队列之后才绘制所需的对象。 I guess that the awt's documentation will explain it. 我想awt的文档将对此进行解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM