在一些快速重复的操作事件调用后,JLabel文本无法正确显示 [英] JLabel text not being displayed correctly after some quickly repeated action event calls

查看:48
本文介绍了在一些快速重复的操作事件调用后,JLabel文本无法正确显示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的Tic Tac Toe项目编写一个图形用户界面,我很享受下面这个小视觉效果的乐趣。每次用户设置CPU播放器并单击完成按钮而忘记设置CPU强度级别时,我都会像下面的代码示例一样显示一条小警告消息。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class TestingStuff implements ActionListener {

JLabel myLabel;
JFrame myFrame;
JButton myButton;
JPanel myPanel;

public TestingStuff() {
    myFrame = new JFrame("Hello");
    myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    myPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    myPanel.setBackground(Color.DARK_GRAY);
    myFrame.add(myPanel, BorderLayout.CENTER);

    myLabel = new JLabel("Hi dear stackoverflow coders!");
    myLabel.setFont(new Font("MV Boli", Font.BOLD, 15));
    myLabel.setForeground(Color.GREEN);
    myPanel.add(myLabel);

    myButton = new JButton("Click me like there's no tomorrow!");
    myButton.addActionListener(this);
    myFrame.add(myButton, BorderLayout.SOUTH);

    myFrame.pack();
    myFrame.setLocationRelativeTo(null);
    myFrame.setVisible(true);
}

    @Override
public void actionPerformed(ActionEvent e) {
    int timerDelay = 1;
    Timer blinkTimer = new Timer(timerDelay, new ActionListener() {
        private int count = 0;
        private int maxTime = 30;
        private String hello = myLabel.getText();
        private int len = hello.length();
        private String s;

        public void actionPerformed(ActionEvent e) {
            if (count * timerDelay >= maxTime) {
                ((Timer) e.getSource()).stop();
            } else {
                myLabel.setVisible(true);
                if (count < len) {
                    s = hello.substring(0, count + 1);
                    myLabel.setText(s);
                }
                count++;
            }
        }
    });
    blinkTimer.start();
}

    public static void main(String[] args) {
    TestingStuff foo = new TestingStuff();
    }
}

尝试重复单击该按钮。

点击前:

点击后:

至少在我的机器上。由于用户没有理由重复单击Done按钮,我并不太担心,但仍然...我想我最终会禁用用户在短小的动画过程中可以点击的每个按钮,以避免意外行为。 我的问题是:有人能解释一下发生了什么吗?为什么我能在7-8次快速点击后看到截短的文本?

推荐答案

更新之间的延迟设置为1毫秒(幸运地获得了准确的😉),因此整个动画大约在30毫秒内完成。

相反,尝试将其设置为30毫秒(~1秒的运行时间)

我还想取消maxTime的概念,您只想继续循环,直到获得所有文本,否则就有点没有意义(IMHO)

可能类似于...

int timerDelay = 30;
Timer blinkTimer = new Timer(timerDelay, new ActionListener() {
    private int count = 0;
    private String hello = myLabel.getText();
    private String s;

    public void actionPerformed(ActionEvent e) {
        if (count >= hello.length()) {
            System.out.println("Done");
             ((Timer) e.getSource()).stop();
        } else {
            System.out.println("Hello");
            myLabel.setVisible(true);
            s = hello.substring(0, count + 1);
            myLabel.setText(s);
            count++;
        }
    }
});
blinkTimer.start();

基于时间的动画

现在,如果您喜欢基于时间的动画,它可能如下所示。

设置为运行1秒,并将使用进度计算来确定应显示多少文本

Timer blinkTimer = new Timer(5, new ActionListener() {

    private String title = myLabel.getText();
    private Duration runtime = Duration.ofSeconds(1);

    private Instant startTime;

    public void actionPerformed(ActionEvent e) {
        if (startTime == null) {
            startTime = Instant.now();
        }
        Duration between = Duration.between(startTime, Instant.now());
        double progress = between.toMillis() / (double)runtime.toMillis();

        if (progress >= 1.0) {
            ((Timer) e.getSource()).stop();
            // Just make sure the text is up-to-date
            myLabel.setText(title);
        } else {
            int count = (int)(title.length() * progress);
            String text = title.substring(0, count);
            myLabel.setText(text);
        }
    }
});
blinkTimer.start();

&qot;顺便说一句,尝试使用您的代码并反复点击按钮:我仍然得到相同的结果&

您不断地创建新的Timer,它们将相互完成。相反,可以禁用该按钮或停止当前运行的Timer,例如...

禁用按钮...

@Override
public void actionPerformed(ActionEvent e) {
    myButton.setEnabled(false);
    Timer blinkTimer = new Timer(5, new ActionListener() {

        private String title = myLabel.getText();
        private Duration runtime = Duration.ofSeconds(1);

        private Instant startTime;

        public void actionPerformed(ActionEvent e) {
            if (startTime == null) {
                startTime = Instant.now();
            }
            Duration between = Duration.between(startTime, Instant.now());
            double progress = between.toMillis() / (double) runtime.toMillis();

            if (progress >= 1.0) {
                ((Timer) e.getSource()).stop();
                // Just make sure the text is up-to-date
                myLabel.setText(title);
                myButton.setEnabled(true);
            } else {
                int count = (int) (title.length() * progress);
                String text = title.substring(0, count);
                myLabel.setText(text);
            }
        }
    });
    blinkTimer.start();
}

取消活动计时器

private Timer blinkTimer;

@Override
public void actionPerformed(ActionEvent e) {
    if (blinkTimer != null) {
        blinkTimer.stop();
        blinkTimer = null;
    }
    blinkTimer = new Timer(5, new ActionListener() {

        private String title = myLabel.getText();
        private Duration runtime = Duration.ofSeconds(1);

        private Instant startTime;

        public void actionPerformed(ActionEvent e) {
            if (startTime == null) {
                startTime = Instant.now();
            }
            Duration between = Duration.between(startTime, Instant.now());
            double progress = between.toMillis() / (double) runtime.toMillis();

            if (progress >= 1.0) {
                ((Timer) e.getSource()).stop();
                // Just make sure the text is up-to-date
                myLabel.setText(title);
                myButton.setEnabled(true);
            } else {
                int count = (int) (title.length() * progress);
                String text = title.substring(0, count);
                myLabel.setText(text);
            }
        }
    });
    blinkTimer.start();
}

和...

哦🤦‍♂️-不要使用标签文本作为标签显示的初始文本-使用您可以控制的内容,否则您会将不完整的文本重新播种到动画中

private String greetingText = "Hi dear stackoverflow coders!";
private Timer blinkTimer;

@Override
public void actionPerformed(ActionEvent e) {
    if (blinkTimer != null) {
        blinkTimer.stop();
        blinkTimer = null;
    }
    blinkTimer = new Timer(5, new ActionListener() {

        private String title = greetingText;
        private Duration runtime = Duration.ofSeconds(5);

        private Instant startTime;

        public void actionPerformed(ActionEvent e) {
            if (startTime == null) {
                startTime = Instant.now();
            }
            Duration between = Duration.between(startTime, Instant.now());
            double progress = between.toMillis() / (double) runtime.toMillis();

            System.out.println(hashCode() + " " + progress);

            if (progress >= 1.0) {
                ((Timer) e.getSource()).stop();
                // Just make sure the text is up-to-date
                myLabel.setText(title);
                myButton.setEnabled(true);
            } else {
                int count = (int) (title.length() * progress);
                String text = title.substring(0, count);
                myLabel.setText(text);
            }
        }
    });
    blinkTimer.start();
}

这篇关于在一些快速重复的操作事件调用后,JLabel文本无法正确显示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆