[英]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));
在OverlappingPanel1
和OverlappingPanel2
类中,因为它们不是必需的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.