【问题标题】:Why is this JPanel not visible?为什么这个 JPanel 不可见?
【发布时间】:2016-07-26 15:15:45
【问题描述】:

我有一个自定义JPanel,在另一个自定义JPanel 后面,在一个JLayeredPane 中。我只想画一次背景JPanel。因为它不会改变。这将节省系统资源。我如何成功地做到这一点?

我知道如果我允许背景 JPanel 像前景 JPanel 一样重复绘制,它会被看到。但这无视我的目标。也就是只画一次。

重新迭代。如何绘制背景 JPanel 一次,然后递归绘制前景 JPanel,而两个 JPanel 都在 JLayeredPane 中看到,其中背景 JPanel 位于前景 JPanel 后面

这是我目前的尝试。这不起作用。这段代码的问题是背景JPanel根本不可见`

这个问题不是重复的,因为人们正在解决不相关的问题。我现在已经让这个问题解决了我想要解决的问题。如果它可以帮助您解决我的问题。那么问题的链接就在这里。 question。 这个问题也有一个糟糕的、毫无意义的答案。我什至仍然尝试过并且不工作。

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

        RepaintManager.currentManager(backPanel).markCompletelyClean(backPanel);

    }

    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){
            if (!drawn){
                super.paintComponent(g);
                g.setColor(Color.red);
                g.fillRect(0, 0, screenSize.width, 200);
                System.out.println("Reccursion");
                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);
        }
    }
}

【问题讨论】:

  • 你怎么知道背景JPanel必须重新绘制?另外,为什么只需要绘制一次?
  • @LakshyaGoyal “你怎么知道背景 JPanel 必须重新绘制?”不要明白你在这里想说什么。 “还有,为什么你只需要画一次?”我不需要。我想要。改善我的程序执行方式。这只是一个mvce。不是我的整个程序
  • @resueman 不是。人们从这个问题中得到了错误的想法。所以我决定不编辑问题,而应该做一个新问题。我会在我的问题中链接到它
  • This would save system resources 你应该问问自己为什么你认为这是必要的......正如我在你的另一个问题的聊天中引用的那样:premature optimization is the root of all evil

标签: java swing jpanel


【解决方案1】:

首先是一些通用的cmets。你不应该:

  1. 扩展 JLayeredPane。
  2. 使用静态变量
  3. 使用 while true 循环

这是否是 MCVE 无关紧要。 MCVE 应该使用正确的结构,否则我们可能会认为您在实际代码中犯了上述错误。

在你的 while 循环中你使用:

repaint();

好吧,您的代码扩展了 JLayeredPane,因此分层窗格的所有层都被绘制。

如果您只想重绘一个面板,则仅在该面板上调用 repaint()。但是,这可能会导致问题,因为您需要确保在对其进行任何绘画之前清除背景,这就是为什么也需要绘制背景的原因。

如果您不想重新绘制整个背景,那么您需要具体说明哪些区域需要重新绘制。查看 Custom Painting 上的 Swing 教程中的部分,该部分展示了如何优化绘制的内容。请注意moveSquare(...) 方法如何在两个不同的区域调用 repaint() 两次。这将导致重新绘制较小的背景区域。

【讨论】:

  • 你能解释一下为什么扩展 JLayeredPane 不好吗?静态变量有什么问题?使用的 while 循环只是一种轻松演示我的问题的方法。在我的真实项目中,我使用了更好的游戏循环。
猜你喜欢
  • 2020-06-10
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多