我正在用 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();
}
这是结果:
您的代码违反了几项 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);
}
}