繁体   English   中英

如何在 Swing 中重叠面板?

[英]How to Overlap Panels in Swing?

我试图让多个JPanel可以“重叠”,也允许我执行自定义绘画。

为此,我使用了MainPanel ,它扩展了JLayeredPane ,据我所知,我已经正确设置了边界和索引。

预期的结果是两个矩形同时绘制到屏幕上。

我得到的结果是在两个OverlappingPanel之一上闪烁,我认为这是来自RepaintManager在哪个面板上绘制(在此处找到)。

我的问题是,如何使用 Swing 正确重叠面板并保留绘画能力?

编辑:

有问题的代码:

import javax.swing.*;
import java.awt.*;

public class Example extends JFrame {
    public static class MainPanel extends JLayeredPane implements Runnable {
        public OverlappingPanel1 overlappingPanel1;
        public OverlappingPanel2 overlappingPanel2;

        Thread mainThread;

        public void startMainThread() {
            mainThread = new Thread(this);
            mainThread.start();
        }

        public MainPanel() {
            this.setPreferredSize(new Dimension(1920,720));
            this.setBackground(Color.BLACK);
            this.setDoubleBuffered(true);

            overlappingPanel1 = new OverlappingPanel1();
            overlappingPanel2 = new OverlappingPanel2();

            overlappingPanel1.setBounds(0,0,1920,720);
            overlappingPanel2.setBounds(0,720/2,1920,720);

            add(overlappingPanel1,1);
            add(overlappingPanel2,2);
        }

        @Override
        public void run() {
            while(mainThread != null) {
                overlappingPanel1.repaint();
                overlappingPanel2.repaint();
            }
        }
    }

    public static class OverlappingPanel1 extends JPanel {
        public OverlappingPanel1() {
            setDoubleBuffered(true);
            setPreferredSize(new Dimension(1920,720));
        }

        public void paint(Graphics g) {
            super.paint(g);
            Graphics2D graphics2D = (Graphics2D) g;

            graphics2D.fillRect(0,0,200,200);
        }
    }

    public static class OverlappingPanel2 extends JPanel {
        public OverlappingPanel2() {
            setDoubleBuffered(true);
            setPreferredSize(new Dimension(1920,720));
        }

        public void paint(Graphics g) {
            super.paint(g);
            Graphics2D graphics2D = (Graphics2D) g;

            graphics2D.fillRect(0,80,200,200);
        }
    }

    public static void main(String[] args) {
        JFrame window = new JFrame();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);

        MainPanel mainPanel = new MainPanel();
        window.add(mainPanel);
        window.setBackground(Color.BLACK);
        window.pack();

        window.setLocationRelativeTo(null);
        window.setVisible(true);

        mainPanel.startMainThread();
    }
}

所以是的,JLayeredPane 将允许 Swing 组件(例如 JPanel)轻松重叠,并且还有其他人创建的布局允许这样做,称为“叠加布局”,但这不是您当前所说的问题想要的。

你的问题是一个XY 问题类型的问题,当最好的解决方案不是以这种方式解决它,而是做 Y,完全不同的事情时,你会问“我如何解决 X 问题”。 在这里,要绘制多个不同的图像,最好的解决方案不是创建和重叠较重的 Swing 组件(例如 JPanel),而是绘制单个 JPanel 并重叠精灵图像。 否则,您只会使您自己和您的代码变得不必要地困难,而不是需要。

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

@SuppressWarnings("serial")
public class Example2 extends JPanel {
    private static final int MY_WIDTH = 1600;
    private static final int MY_HEIGHT = 720;
    List<Rectangle> rectangles = new ArrayList<>();

    public Example2() {
        setPreferredSize(new Dimension(MY_WIDTH, MY_HEIGHT));
        setBackground(Color.WHITE);
        
        rectangles.add(new Rectangle(0, 0, 200, 200));
        rectangles.add(new Rectangle(0, 80 + MY_HEIGHT / 2, 200, 200));
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        for (Rectangle rectangle : rectangles) {
            g2.fill(rectangle);
        }
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Example2 example = new Example2();
            
            JFrame frame = new JFrame("GUI");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(example);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

是的,正如评论中所建议的那样,覆盖paintComponent而不是paint 这降低了可能来自绘制子组件或边框的不良副作用的风险,并且还允许在您执行 animation 时进行自动双缓冲。

此外,在事件驱动的 GUI 程序中, while (true)循环不是一个健康的结构,而不是像您编写的那样。 如果您需要在 Swing 程序中重复操作(在您的示例中还没有),请改用Swing 计时器

所以这样做会给你很好的灵活性。 例如,如果您想修改上述程序以允许在鼠标单击时添加形状,这样做很容易:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

@SuppressWarnings("serial")
public class Example3 extends JPanel {
    private static final int MY_WIDTH = 1600;
    private static final int MY_HEIGHT = 720;
    List<ColorShape> colorShapes = new ArrayList<>();

    public Example3() {
        setPreferredSize(new Dimension(MY_WIDTH, MY_HEIGHT));
        setBackground(Color.WHITE);
        
        addMouseListener(new MyMouse());
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        for (ColorShape colorShape : colorShapes) {
            colorShape.draw(g2);
        }
    }
    
    private class MyMouse extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            // create a random color
            float hue = (float) Math.random();
            float saturation = 1f;
            float brightness = (float) (0.5 * Math.random() + 0.5);
            Color color = Color.getHSBColor(hue, saturation, brightness);

            // create a new ColorShape, add to list, and repaint:
            colorShapes.add(new ColorShape(e.getPoint(), color));
            repaint();
        }
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Example3 example = new Example3();
            
            JFrame frame = new JFrame("GUI");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(example);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}
class ColorShape {
    private int width = 80;
    private Point location;
    private Color color;
    private Shape shape;

    public ColorShape(Point location, Color color) {
        this.location = location;
        this.color = color;
        int x = location.x - width / 2;
        int y = location.y - width / 2;
        shape = new Ellipse2D.Double(x, y, width, width);
    }
    
    public void draw(Graphics2D g2) {
        g2.setColor(color);
        g2.fill(shape);
    }
    
    public Point getLocation() {
        return location;
    }
}

setBounds(int x,int y, int width, int height)中的最后两个参数是面板的宽度和高度。 在您的情况下,这些是矩形的尺寸,因此您应该将它们设置为200 ,如下所示:

    overlappingPanel1.setBounds(0,0,200,200);
    overlappingPanel2.setBounds(0,720/2,200,200);

另外,删除setPreferredSize(new Dimension(1920,720)); OverlappingPanel1OverlappingPanel2类中,因为它们不是必需的。

暂无
暂无

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

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