Не получается вывод, как ожидалось в Swing

1

Я знаю многопоточность, но не в огромном объеме, и я думаю, что проблема заключается в многопоточности. Я вызываю метод для установки текста меток, вызывая новый поток и оставляя его пустым через определенное время. Я получаю желаемый результат каждый раз, но не только то место, которое я собираюсь показать вам по моей части кода. Я ожидаю, что это сообщение должно быть установлено и исчезло через указанное время, и окно должно быть сведено к минимуму после этого времени. Но то, что на самом деле происходит, когда он переходит к другому запуску основного потока, запускается и переходит на спящий режим в течение 5 секунд, и сообщение не появляется, и после 5 секунд окно становится минимальным, не показывая сообщение, которое я устанавливаю на ярлыке.

(Основной поток)

Validation.setMessageOnLabel("Username and password has been copied", jLabel15,1.5F);
try {
    Thread.sleep(5000);
} catch (InterruptedException ex) {
    Logger.getLogger(PasswordManager.class.getName()).log(Level.SEVERE, null, ex);
}
setState(ICONIFIED);

validation.java(setMessageOnLabel())

static public void setMessageOnLabel(final String msg, final JLabel label, final float time)
{
    new Thread(new Runnable() {

        @Override
        public void run() {

            label.setText(msg);

            try {
                Thread.sleep((long) (time*1000));
            } catch (InterruptedException ex) {
                Logger.getLogger(PasswordManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            label.setText("");
        }
    }).start();
}
  • 3
    Swing не является потокобезопасным, и это является прямым нарушением политики потоков Swing. Все взаимодействия с компонентами GUI должны выполняться на EDT. Ваш первый фрагмент кода также спит EDT в течение пяти секунд, блокируя графический интерфейс. Вкратце прочитайте все это .
Теги:
multithreading
swing

3 ответа

3
Лучший ответ

Не используйте Thread.sleep(5000); , которые блокируют EDT.

Для этого вы можете использовать Timer качания, рассмотрите следующий пример:

import java.awt.BorderLayout;
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.Timer;

public class TestFrame extends JFrame {

    private JLabel lbl;

    public TestFrame() {
        init();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void init() {
        lbl = new JLabel(" ");
        JButton setText = new JButton("setText");
        setText.addActionListener(getActionListener());
        add(lbl);
        add(setText,BorderLayout.SOUTH);
    }

    private ActionListener getActionListener() {
        return new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                lbl.setText("wait...");
                Timer t = new Timer(5000, new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        lbl.setText("");
                        setState(JFrame.ICONIFIED);
                    }
                });
                t.setRepeats(false);
                t.start();
            }
        };
    }

    public static void main(String args[]) {
        new TestFrame();
    }

}
  • 2
    Замечательно, что вы говорили о Event Dispatcher Thread но, похоже, ваш основной метод отсутствует (проще говоря, вам самим никогда не хотелось запускать графический интерфейс в EDT, оборачивая содержимое основного метода внутри SwingUtilities.invokeLater(...) ) Более того, пожалуйста, для будущих публикаций, всегда старайтесь использовать BorderLayout.PAGE_END вместо BorderLayout.SOUTH так как Java поощряет его использование начиная с JDK 1.4
  • 1
    @nIcEcOw "... так как Java поощряет ее использование начиная с JDK 1.4 " .. и вы также поощряете и меня (хотя не начиная с 1.4, поскольку вы только предупредили меня об этом позже). Продолжайте хорошую работу. :)
Показать ещё 6 комментариев
4

Поскольку вы вызываете setState() напрямую, я предполагаю, что первый фрагмент кода является частью JFrame. В этом случае вы, скорее всего, отправляете поток отправки событий в режим ожидания в течение 5 секунд и, таким образом, предотвращаете обновление экрана за это время.

Поместите сон в другой поток или используйте swing worker вместо этого и вызовите setState() в EDT в методе обратного вызова рабочего, поскольку setState() не помечен как потокобезопасный, и вызов его в потоке, отличном от EDT, может привести к неожиданное поведение.

Из связанного учебника:

Некоторые методы компонента Swing помечены как "потокобезопасные" в спецификации API; они могут быть безопасно вызваны из любого потока. Все остальные методы компонента Swing должны быть вызваны из потока отправки событий. Программы, которые игнорируют это правило, могут нормально функционировать большую часть времени, но подвержены непредсказуемым ошибкам, которые трудно воспроизвести.

  • 4
    +1 только за цитату.
  • 0
    спасибо, что получил, я не могу проголосовать, потому что для этого нужно 15 баллов. Большое спасибо, я понял.
Показать ещё 1 комментарий
-2

При работе с компонентами Swing вы не используете такие потоки. Вместо этого запустите свой собственный SwingWorker.

public class MySwingWorker extends SwingWorker<Object, Object> {

    @Override
    public Object doInBackground() {
        //your code here
        //dont forget to repaint changed component or validate parent of it, 
        //if your text dont shows up.
        return null;
    }
}

вы также можете выполнить свою собственную runnable через SwingUtilites

    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            //again your code here...
        }
    });
  • 3
    Вы, конечно, не должны делать ничего из этого из метода doInBackground . Swing не является потокобезопасным, а перерисовка или проверка из рабочего потока вызовет неопределенное поведение.
  • 0
    Swing не безопасен для потоков, я согласен с этим, но SwingWorker и SwingUtilities не связываются с EDT. Они предназначены для взаимодействия с компонентами Swing. Использование SwingWorker для загрузки данных и обновления панели прогресса этой операции - пример книги.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню