Guest
Swing UI dupliziert Elemente im Hintergrund
Post
by Guest » 07 Jan 2025, 05:22
Ich versuche, ein Overlay für ein Spiel zu erstellen, das über einen einfachen Timer mit Start-/Reset- und Stopp-Tastenkombinationen verfügt. Verwendet einen benutzerdefinierten Fortschrittsbalken, um den Timer-Fortschritt und einige andere wichtige Punkte im Timer anzuzeigen.
Aus irgendeinem unbekannten Grund führen das Starten des Timers, der Timer-Tick und das Stoppen des Timers zu Geisterbildern auf der Benutzeroberfläche Probleme, bei denen durch Ändern der Fenstergröße das Fenster vorübergehend gelöscht wird, bis zur nächsten Aktion, die das Geisterbild verursacht.
Was verursacht dieses Geisterbild und wie kann ich es verhindern?
Screenshots:
Minimale Reproduktion:
Code: Select all
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;
@Slf4j
public class SmudgeTimerPanel extends JPanel {
private static final int TIMER_SPIRIT = 180; // seconds
private static final int TIMER_DEMON = 60; // seconds
private static final int TIMER_OTHER = 90; // seconds
private final CustomProgressBar progressBar;
private final JLabel timeRemainingLabel;
private final JLabel statusLabel;
private final JLabel ghostLabel;
private Timer timer;
private int remainingTime;
private boolean isRunning;
public SmudgeTimerPanel() {
setLayout(new GridBagLayout());
setBackground(new Color(50, 50, 50, 150)); // Transparent gray background
progressBar = new CustomProgressBar(0, TIMER_SPIRIT);
timeRemainingLabel = new JLabel("3:00");
timeRemainingLabel.setForeground(Color.WHITE);
timeRemainingLabel.setBackground(new Color(0, 0, 0, 0));
timeRemainingLabel.setFont(timeRemainingLabel.getFont().deriveFont(24f));
statusLabel = new JLabel();
statusLabel.setOpaque(true);
statusLabel.setBackground(Color.RED);
statusLabel.setPreferredSize(new Dimension(10, 10));
ghostLabel = new JLabel("None");
ghostLabel.setForeground(Color.WHITE);
ghostLabel.setFont(ghostLabel.getFont().deriveFont(24f));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(10, 10, 10, 10);
add(progressBar, gbc);
gbc.gridy = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.CENTER;
JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
statusPanel.setOpaque(false);
statusPanel.add(statusLabel);
statusPanel.add(timeRemainingLabel);
add(statusPanel, gbc);
gbc.gridy = 2;
gbc.gridx = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
add(ghostLabel, gbc);
gbc.gridy = 3;
gbc.fill = GridBagConstraints.HORIZONTAL;
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
buttonPanel.setOpaque(false);
JButton startResetButton = new JButton("Start/Reset Timer");
startResetButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
resetTimer(TIMER_SPIRIT);
}
});
JButton stopButton = new JButton("Stop Timer");
stopButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stopTimer();
}
});
buttonPanel.add(startResetButton);
buttonPanel.add(stopButton);
add(buttonPanel, gbc);
}
public void resetTimer(int timerDuration) {
if (timer != null) {
timer.cancel();
}
remainingTime = timerDuration;
isRunning = true;
updateGhostLabel();
updateTimeDisplay();
progressBar.setMaximum(timerDuration);
progressBar.setValue(timerDuration);
statusLabel.setBackground(Color.GREEN);
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
SwingUtilities.invokeLater(() -> {
if (remainingTime > 0) {
remainingTime--;
progressBar.setValue(remainingTime);
updateTimeDisplay();
updateGhostLabel();
} else {
stopTimer();
}
});
}
}, 0, 1000);
}
public void stopTimer() {
if (timer != null) {
timer.cancel();
}
isRunning = false;
statusLabel.setBackground(Color.RED);
}
public void startOrResetTimer(String ghostType) {
resetTimer(TIMER_SPIRIT);
}
private void updateTimeDisplay() {
int minutes = remainingTime / 60;
int seconds = remainingTime % 60;
timeRemainingLabel.setText(String.format("%d:%02d", minutes, seconds));
timeRemainingLabel.setBackground(new Color(0, 0, 0, 0));
}
private void updateGhostLabel() {
if (remainingTime > TIMER_OTHER) {
ghostLabel.setText("Spirit");
} else if (remainingTime > TIMER_DEMON) {
ghostLabel.setText("All Others");
} else {
ghostLabel.setText("Demon");
}
}
public boolean isTimerRunning() {
return isRunning;
}
@Slf4j
private static class CustomProgressBar extends JComponent {
private int value;
private int maximum;
public CustomProgressBar(int min, int max) {
this.value = min;
this.maximum = max;
setPreferredSize(new Dimension(300, 20));
setMinimumSize(new Dimension(300, 20));
}
public void setValue(int value) {
this.value = Math.min(value, maximum);
repaint();
}
public void setMaximum(int maximum) {
this.maximum = maximum;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
log.info("Width: {}, Height: {}", width, height);
// Draw background
g2d.setColor(Color.GRAY);
g2d.fillRect(0, 0, width, height);
// Draw progress
int progressWidth = (int) ((value / (double) maximum) * width);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, progressWidth, height);
// Draw tick marks
g2d.setColor(Color.BLACK);
int demonMark = (int) (((TIMER_SPIRIT - TIMER_DEMON) / (double) maximum) * width);
int otherMark = (int) ((TIMER_OTHER / (double) maximum) * width);
g2d.drawLine(demonMark, 0, demonMark, height);
g2d.drawLine(otherMark, 0, otherMark, height);
}
}
// Test the SmudgeTimerPanel in its own JFrame
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Smudge Timer Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
SmudgeTimerPanel timerPanel = new SmudgeTimerPanel();
frame.add(timerPanel);
frame.setVisible(true);
});
}
}
1736223743
Guest
Ich versuche, ein Overlay für ein Spiel zu erstellen, das über einen einfachen Timer mit Start-/Reset- und Stopp-Tastenkombinationen verfügt. Verwendet einen benutzerdefinierten Fortschrittsbalken, um den Timer-Fortschritt und einige andere wichtige Punkte im Timer anzuzeigen. Aus irgendeinem unbekannten Grund führen das Starten des Timers, der Timer-Tick und das Stoppen des Timers zu Geisterbildern auf der Benutzeroberfläche Probleme, bei denen durch Ändern der Fenstergröße das Fenster vorübergehend gelöscht wird, bis zur nächsten Aktion, die das Geisterbild verursacht. Was verursacht dieses Geisterbild und wie kann ich es verhindern? Screenshots: [img]https://i.sstatic.net/A23eUEb8.png[/img] [img]https://i.sstatic.net/9QS6UXkK.png[/img] Minimale Reproduktion: [code]import lombok.extern.slf4j.Slf4j; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Timer; import java.util.TimerTask; @Slf4j public class SmudgeTimerPanel extends JPanel { private static final int TIMER_SPIRIT = 180; // seconds private static final int TIMER_DEMON = 60; // seconds private static final int TIMER_OTHER = 90; // seconds private final CustomProgressBar progressBar; private final JLabel timeRemainingLabel; private final JLabel statusLabel; private final JLabel ghostLabel; private Timer timer; private int remainingTime; private boolean isRunning; public SmudgeTimerPanel() { setLayout(new GridBagLayout()); setBackground(new Color(50, 50, 50, 150)); // Transparent gray background progressBar = new CustomProgressBar(0, TIMER_SPIRIT); timeRemainingLabel = new JLabel("3:00"); timeRemainingLabel.setForeground(Color.WHITE); timeRemainingLabel.setBackground(new Color(0, 0, 0, 0)); timeRemainingLabel.setFont(timeRemainingLabel.getFont().deriveFont(24f)); statusLabel = new JLabel(); statusLabel.setOpaque(true); statusLabel.setBackground(Color.RED); statusLabel.setPreferredSize(new Dimension(10, 10)); ghostLabel = new JLabel("None"); ghostLabel.setForeground(Color.WHITE); ghostLabel.setFont(ghostLabel.getFont().deriveFont(24f)); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(10, 10, 10, 10); add(progressBar, gbc); gbc.gridy = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.CENTER; JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); statusPanel.setOpaque(false); statusPanel.add(statusLabel); statusPanel.add(timeRemainingLabel); add(statusPanel, gbc); gbc.gridy = 2; gbc.gridx = 0; gbc.fill = GridBagConstraints.NONE; gbc.anchor = GridBagConstraints.CENTER; add(ghostLabel, gbc); gbc.gridy = 3; gbc.fill = GridBagConstraints.HORIZONTAL; JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); buttonPanel.setOpaque(false); JButton startResetButton = new JButton("Start/Reset Timer"); startResetButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { resetTimer(TIMER_SPIRIT); } }); JButton stopButton = new JButton("Stop Timer"); stopButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { stopTimer(); } }); buttonPanel.add(startResetButton); buttonPanel.add(stopButton); add(buttonPanel, gbc); } public void resetTimer(int timerDuration) { if (timer != null) { timer.cancel(); } remainingTime = timerDuration; isRunning = true; updateGhostLabel(); updateTimeDisplay(); progressBar.setMaximum(timerDuration); progressBar.setValue(timerDuration); statusLabel.setBackground(Color.GREEN); timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { SwingUtilities.invokeLater(() -> { if (remainingTime > 0) { remainingTime--; progressBar.setValue(remainingTime); updateTimeDisplay(); updateGhostLabel(); } else { stopTimer(); } }); } }, 0, 1000); } public void stopTimer() { if (timer != null) { timer.cancel(); } isRunning = false; statusLabel.setBackground(Color.RED); } public void startOrResetTimer(String ghostType) { resetTimer(TIMER_SPIRIT); } private void updateTimeDisplay() { int minutes = remainingTime / 60; int seconds = remainingTime % 60; timeRemainingLabel.setText(String.format("%d:%02d", minutes, seconds)); timeRemainingLabel.setBackground(new Color(0, 0, 0, 0)); } private void updateGhostLabel() { if (remainingTime > TIMER_OTHER) { ghostLabel.setText("Spirit"); } else if (remainingTime > TIMER_DEMON) { ghostLabel.setText("All Others"); } else { ghostLabel.setText("Demon"); } } public boolean isTimerRunning() { return isRunning; } @Slf4j private static class CustomProgressBar extends JComponent { private int value; private int maximum; public CustomProgressBar(int min, int max) { this.value = min; this.maximum = max; setPreferredSize(new Dimension(300, 20)); setMinimumSize(new Dimension(300, 20)); } public void setValue(int value) { this.value = Math.min(value, maximum); repaint(); } public void setMaximum(int maximum) { this.maximum = maximum; repaint(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int width = getWidth(); int height = getHeight(); log.info("Width: {}, Height: {}", width, height); // Draw background g2d.setColor(Color.GRAY); g2d.fillRect(0, 0, width, height); // Draw progress int progressWidth = (int) ((value / (double) maximum) * width); g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, progressWidth, height); // Draw tick marks g2d.setColor(Color.BLACK); int demonMark = (int) (((TIMER_SPIRIT - TIMER_DEMON) / (double) maximum) * width); int otherMark = (int) ((TIMER_OTHER / (double) maximum) * width); g2d.drawLine(demonMark, 0, demonMark, height); g2d.drawLine(otherMark, 0, otherMark, height); } } // Test the SmudgeTimerPanel in its own JFrame public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Smudge Timer Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 300); SmudgeTimerPanel timerPanel = new SmudgeTimerPanel(); frame.add(timerPanel); frame.setVisible(true); }); } } [/code]