代码之家  ›  专栏  ›  技术社区  ›  Dromlius

JPanel透支重叠的JComcoBox

  •  1
  • Dromlius  · 技术社区  · 1 年前

    我正在用Java编写一个小型“游戏”,在其中我使用 面板 作为主渲染屏幕。 我还包括一个 下拉框 在渲染JPanel上方显示下拉选项。但当我尝试扩展JComboBox时,它会 透支的 来自JPanel。

    我试过了 setComponentZOrder() 但这只会使组件在LayoutManager中互相吞噬。和 J分层窗格 似乎也不起作用。

    我如何制作 “实时重新定义” J面板没有过度绘制重叠的组件?

    简化示例:

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

    结果是:

    enter image description here

    1 回复  |  直到 1 年前
        1
  •  2
  •   Hovercraft Full Of Eels    1 年前

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

    • 不要在组件上使用getGraphics来获取Graphics对象。该对象将是短暂的,并且可能在某个时刻为null。
    • 不要从后台线程或任何其他非Swing事件调度线程中进行Swing调用。

    相反

    • 使用Swing Timer来驱动动画,
    • 在paintComponent方法中进行绘制。
    • 一定要打电话给 super.paintComponent(g) 方法覆盖组件,以便可以进行内务绘制
    • 请注意,应该覆盖JPanel(或从JComponent扩展的其他对象)的paintComponent方法,而不是覆盖绘制方法,因为默认情况下,paintComponent会为您提供双重缓冲,使动画更平滑。

    例如

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.Color;
    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 static final Color BACKGROUND = Color.MAGENTA;
        private int x = 0;
        private int y = 0;
        private int deltaX = DELTA_X;
        private int deltaY = DELTA_Y;
    
        public AnimationPanel() {
            setBackground(BACKGROUND);
            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);
        }
    }