Могу ли я использовать нить в таймере? - PullRequest
0 голосов
/ 27 мая 2019

этот код начинается с кнопки запуска, но этот код используется, если выбран обратный отсчет радиокнопки, когда обратный отсчет равен 0, появляется второй кадр, и он должен менять цвета в соответствии со скоростью, введенной пользователем, называемой "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);
    }
    }
});`

1 Ответ

0 голосов
/ 27 мая 2019

Ваш код нарушает правила потоков Swing:

  • Вы делаете вызовы Swing из фоновых потоков, и это опасно и может привести к непредсказуемым вызовам исключений.
  • Вы используете java.uti.Timer и должны использовать javax.swing.Timer, так как повторяющийся код последнего выполняется в потоке событий Swing.
  • У вас есть while (true) петли, которые не принадлежат. Таймер берет на себя функцию цикла.
  • Вы постоянно создаете и запускаете таймер Swing из цикла while - почему?

Например, следующий код использует JSlider для установки частоты мигания и флажок для запуска / остановки таймера качания, который мигает цветом фона основного JPanel:

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 просто вызовите его метод 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 использует 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
    }
}
...