I'm writing a small "Game" in Java, in which I am using a JPanel as the main rendering screen. I've also included a JComboBox above the rendering-JPanel for dropdown-options. But when I try to expand the JComboBox it gets overdrawn from the JPanel.
I've tried setComponentZOrder() but this only made the Component eat each other in the LayoutManager. And JLayeredPane didn't seem to work either.
How can I make a "realtime redered" JPanel not overdraw overlapping components?
Simplified example:
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();
}
This is the result:
Your code is breaking several Swing rules, including:
Instead,
super.paintComponent(g)
method in your paintComponent override so that housekeeping painting can be doneFor example
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);
}
}