Пользовательский интерфейс Swing дублирует элементы в фоновом режимеJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Пользовательский интерфейс Swing дублирует элементы в фоновом режиме

Сообщение Anonymous »

пытаюсь создать оверлей для игры с простым таймером с сочетаниями клавиш запуска/сброса и остановки. Использует настраиваемый индикатор выполнения для отображения прогресса таймера и некоторых других ключевых моментов таймера.
По неизвестной причине запуск таймера, тиканье таймера и остановка таймера приводят к появлению ореолов пользовательского интерфейса. проблемы, при которых изменение размера окна временно очищает его до следующего действия, вызывающего ореолы.
Что вызывает ореолы и как их предотвратить?
Скриншоты:
Изображение
Изображение

Минимальный воспроизведение:
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);
});
}
}


Подробнее здесь: https://stackoverflow.com/questions/793 ... background
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»