【问题标题】:Can I use Thread in Timer?我可以在定时器中使用线程吗?
【发布时间】:2019-05-27 18:00:49
【问题描述】:

此代码以开始按钮开头,但如果选择了单选按钮倒计时,则使用此代码,当倒计时为 0 时,第二个 Frame 出现并且应该按照用户输入的速度改变颜色,称为“brzinaTreperenja2”(对象转换为 int 然后乘以 1000 毫秒),我的颜色为红色。当我没有第二个 actionListener 并且闪烁以 1 秒的速度工作时,确实会发生闪烁,但是当我这样做时,程序会冻结。你能帮我解决这个问题吗?

start.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        if(countdown.isSelected()){

        final Timer p = new Timer();
        display.setFont(new Font("Ariel", Font.BOLD,25));
        display.setBounds(150,75,120,20);
        p.scheduleAtFixedRate(new TimerTask(){
        int i = Integer.parseInt(odbrojavanje.getText());
        @Override
        public void run(){
        display.setText(""+(i--));
        if(i<0){
            p.cancel();
            drugi.setVisible(true);
            Thread t = new Thread();
            while(true){
                ActionListener al3 = new ActionListener(){
                public void actionPerformed(ActionEvent h){
            drugi.getContentPane().setBackground(boja.getBackground());
                try {
                    t.sleep(brzinaTreperenja2);
                } catch (InterruptedException ex) {
                    Logger.getLogger(PrviProzor.class.getName()).log(Level.SEVERE, null, ex);
                }
            drugi.getContentPane().setBackground(Color.red);
                try {
                    t.sleep(brzinaTreperenja2);
                } catch (InterruptedException ex) {
                    Logger.getLogger(PrviProzor.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            };
                javax.swing.Timer p = new javax.swing.Timer(1000, al3);
                p.start();
            }
        }
        }
        },0,1000);
    }
    }
});`

【问题讨论】:

  • 请在您的问题中添加代码,不要发布链接。
  • 我编辑了问题

标签: java swing actionlistener


【解决方案1】:

您的代码违反了 Swing 线程规则:

  • 您正在从后台线程进行 Swing 调用,这样做很危险,并且可能会导致无法预测地抛出异常。
  • 您正在使用java.uti.Timer,并且应该使用javax.swing.Timer,因为后者的重复代码在Swing 事件线程上运行。
  • 您有不属于的while (true) 循环。计时器接管了循环的功能。
  • 您在 while 循环中反复创建和启动 Swing 计时器 -- 为什么?

例如,以下代码使用 JSlider 设置闪烁频率,并使用复选框来启动/停止闪烁主 JPanel 背景颜色的 Swing Timer:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class BlinkEg extends JPanel {
    public static final Color COLOR = Color.RED;
    private JSlider slider = new JSlider(100, 1000, 500);
    private JCheckBox blinkBox = new JCheckBox("Blink");
    private Timer timer = new Timer(slider.getValue(), new TimerListener());

    public BlinkEg() {
        slider.setOpaque(false);
        slider.setMajorTickSpacing(200);
        slider.setMinorTickSpacing(10);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        setPreferredSize(new Dimension(400, 200));
        JPanel bottomPanel = new JPanel();
        bottomPanel.add(blinkBox);
        bottomPanel.setOpaque(false);

        blinkBox.setOpaque(false);
        blinkBox.addItemListener(evt -> {
            if (evt.getStateChange() == ItemEvent.SELECTED) {
                timer.start();
            } else {
                timer.stop();
                setBackground(null);
            }
        });

        slider.addChangeListener(evt -> {
            int value = slider.getValue();
            timer.setDelay(value);
        });

        setLayout(new BorderLayout());
        add(slider);
        add(bottomPanel, BorderLayout.PAGE_END);
    }

    private class TimerListener implements ActionListener {
        private boolean drawColor = false;

        @Override
        public void actionPerformed(ActionEvent e) {
            Color color = drawColor ? null : COLOR;
            BlinkEg.this.setBackground(color);
            drawColor = !drawColor;
        }
    }

    private static void createAndShowGui() {
        BlinkEg mainPanel = new BlinkEg();

        JFrame frame = new JFrame("BlinkEg");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

请注意,要更改 Swing Timer 的计时,只需调用其setDelay(...) 方法:

// timer changed to rate set by JSlider:
slider.addChangeListener(evt -> {
    int value = slider.getValue();
    timer.setDelay(value);
});

要开始和停止闪烁,只需启动和停止计时器:

// timer start and stopped based on JCheckBox state
blinkBox.addItemListener(evt -> {
    if (evt.getStateChange() == ItemEvent.SELECTED) {
        timer.start();
    } else {
        timer.stop();
        setBackground(null);  // so always stops with baseline color
    }
});

Swing Timer 使用一个 ActionListener,它使用一个布尔值来决定将背景设置为哪种颜色,然后交换布尔值的值

private class TimerListener implements ActionListener {
    private boolean drawColor = false;

    @Override
    public void actionPerformed(ActionEvent e) {
        // choose color based on the state of drawColor
        Color color = drawColor ? null : COLOR;
        BlinkEg.this.setBackground(color);

        drawColor = !drawColor; // now toggle drawColor's boolean value
    }
}

【讨论】:

  • 我想改变闪烁背景的速度,我让一个线程休眠了用户选择的几秒钟,实际上不知道如何编写这段代码
  • 我在问题中说,当我没有第二个 actionListener 时,代码可以工作,但不会以用户选择的速度闪烁,而是每秒闪烁一次
  • @Jovaaa:你把事情搞得太复杂了,而且再次违反了 Swing 线程规则。请参阅编辑以回答有关更改计时器速度的问题。
猜你喜欢
  • 2023-03-29
  • 2018-06-25
  • 2010-10-09
  • 1970-01-01
  • 2015-09-11
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
相关资源
最近更新 更多