EventQueue.invokeLater () имеет некоторые ошибки - PullRequest
1 голос
/ 02 октября 2019

Когда этот код запускается, все работает нормально, но проблема возникает в основном, когда я изменяю код внутри, который будет использоваться с EventQueue.invokeLater()

package dav.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JProgressBar;

public class SplashWindow extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private JPanel contentPane;
    private JProgressBar progressBar;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        //from here...
        final SplashWindow frame = new SplashWindow();                  frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        for (int i = 0; i < 100; i++) {
            frame.setProgress(i);
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
//to here...
    }

    /**
     * Create the frame.
     */
    public SplashWindow() {
        setUndecorated(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        JPanel panel = new JPanel();
        contentPane.add(panel, BorderLayout.CENTER);

        progressBar = new JProgressBar();
        progressBar.setMaximum(100);
        progressBar.setValue(0);
        progressBar.setForeground(Color.CYAN);

        panel.setBackground(Color.BLUE);
        GroupLayout gl_panel = new GroupLayout(panel);
        gl_panel.setHorizontalGroup(gl_panel.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_panel.createSequentialGroup().addContainerGap()

                        .addComponent(progressBar, GroupLayout.DEFAULT_SIZE, 420, Short.MAX_VALUE).addContainerGap()));
        gl_panel.setVerticalGroup(gl_panel.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_panel
                        .createSequentialGroup().addGap(245).addComponent(progressBar, GroupLayout.PREFERRED_SIZE,
                                GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                        .addContainerGap(31, Short.MAX_VALUE)));
        panel.setLayout(gl_panel);

    }

    public void setProgress(int i) {
        progressBar.setValue(i);
        if (i+1>=progressBar.getMaximum()){
            dispose();}
    }
}

, изменяя основной метод на

public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
final SplashWindow frame = new SplashWindow();                  frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                    for (int i = 0; i < 100; i++) {
                        frame.setProgress(i);
                        try {
                            Thread.sleep(100);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

    }

Не исключение, но оно не работает должным образом, и, как вы все знаете, использование EventQueue предпочтительнее, чем работа внутри основного метода из-за EDT.

Но работает следующее:

final SplashWindow frame = new SplashWindow();
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        for (int i = 0; i < 100; i++) {
            frame.setProgress(i);
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

Хотя индикатор выполнения в какой-то момент обнуляется и упс! NullPointerException брошен. Как видите, я делаю кастом SplashWindow вместо встроенного. Нужна помощь и, пожалуйста, не указывайте некоторые библиотеки.

1 Ответ

3 голосов
/ 02 октября 2019

Нет ничего плохого в EventQueue.invokeLater, все в том, как вы его используете.

Это ...

EventQueue.invokeLater(new Runnable() {
    public void run() {
        //...
    }
});

говорит, что в какой-то момент в будущем, сделайтеэто. НО, вы немедленно проследите за этим с помощью ...

for (int i = 0; i < 100; i++) {
    frame.setProgress(i);
    try {
        Thread.sleep(100);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

, который, вероятно, будет выполнен ДО того, как invokeLater сможет запустить.

В целом лучшим решением было бывместо этого используйте SwingWorker и запустите его в EventQueue.invokeLater, как только вы убедитесь, что состояние пользовательского интерфейса установлено.

Помните, что Swing не только однопоточный, он НЕ является поточно-ориентированным. Это означает, что вы не только не должны блокировать основной поток пользовательского интерфейса (т. Е. Поток диспетчеризации событий), но и не должны обновлять пользовательский интерфейс или все, на что он опирается, извне

См. Рабочие потокии SwingWorker для более подробной информации

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...