JPanel 过度绘制重叠的 JComcoBox

问题描述 投票:0回答:1

我正在用 Java 编写一个小型“游戏”,其中我使用 JPanel 作为主渲染屏幕。 我还在渲染 JPanel 上方添加了一个 JComboBox 用于下拉选项。但是当我尝试扩展 JComboBox 时,它会从 JPanel 中获得 overdrawn

我尝试过 setComponentZOrder() 但这只会使组件在 LayoutManager 中互相吞噬。而且 JLayeredPane 似乎也不起作用。

如何制作“实时重新渲染” JPanel 不过度绘制重叠组件?

简化示例:

public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setLayout(new BorderLayout());

    JPanel renderScreen = new JPanel();
    Thread drawingThread = new Thread(() -> {
        while (true) {
            Graphics graphics = renderScreen.getGraphics();
            graphics.setColor(Color.MAGENTA);
            graphics.fillRect(0, 0, renderScreen.getWidth(), renderScreen.getHeight());

            try {Thread.sleep(5);} catch (InterruptedException ie) {}
        }
    });
    frame.add(renderScreen, BorderLayout.CENTER);

    JComboBox<String> dropdown = new JComboBox<>(new String[]{"Hello", "StackOverflow", "please", "help"});
    frame.add(dropdown, BorderLayout.NORTH);

    frame.setComponentZOrder(renderScreen,1);
    frame.setComponentZOrder(dropdown,0);

    frame.setVisible(true);

    drawingThread.start();

}

这是结果:

java swing user-interface graphics drawing
1个回答
0
投票

您的代码违反了几项 Swing 规则,包括:

  • 不要在组件上使用 getGraphics 来获取 Graphics 对象。该对象的生命周期很短,并且可能在某个时候为空。
  • 不要从后台线程或任何其他非 Swing 事件调度线程中进行 Swing 调用。

相反,请使用 Swing Timer 并在 PaintComponent 方法中进行绘图。例如

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.*;

public class SwingGui01 extends JPanel {
    private JComboBox<String> comboBox = new JComboBox<>(new String[]{"One", "Two", "Three", "Four", "Five"});
    private AnimationPanel animationPanel = new AnimationPanel();

    public SwingGui01() {
        setLayout(new BorderLayout());
        add(comboBox, BorderLayout.PAGE_START);
        add(animationPanel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Swing GUI 01");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new SwingGui01());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

class AnimationPanel extends JPanel {
    private static final int DELTA_X = 5;
    private static final int DELTA_Y = DELTA_X;
    private static final int PREF_W = 400;
    private static final int PREF_H = 300;
    private static final int ANIMATION_DELAY = 20;
    private int x = 0;
    private int y = 0;
    private int deltaX = DELTA_X;
    private int deltaY = DELTA_Y;

    public AnimationPanel() {
        Timer timer = new Timer(ANIMATION_DELAY, e -> {
            if (y > getHeight() - 50 ) {
                deltaY = -DELTA_Y;
            } else if (y < 0) {
                deltaY = DELTA_Y;
            }
            if (x > getWidth() - 50) {
                deltaX = -DELTA_X;
            } else if (x < 0) {
                deltaX = DELTA_X;
            }
            x += deltaX;
            y += deltaY;
            repaint();
        });
        timer.start();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(PREF_W, PREF_H);
    }

    @Override
    protected void paintComponent(java.awt.Graphics g) {
        super.paintComponent(g);
        g.fillOval(x, y, 50, 50);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.