Обновить JFrame из другого метода - PullRequest
0 голосов
/ 19 сентября 2019

У меня есть файл .csv, который содержит полные пиксельные данные из 60000 рукописных цифр (набор данных mnist рукописных чисел).Функция train () вызывается при нажатии кнопки.Из функции train () я бы хотел, чтобы каждая из 60000 цифр отображалась на экране.Код работает отлично, я просто не могу заставить JFrame обновляться из метода train ().

Я протестировал код, и он на 100% работает как задумано.Я просто не могу заставить JFrame обновляться, находясь в функции train ().

    public void trainMenu() {
        JButton trainBtn = new JButton("Train");
        JLabel otp = new JLabel();
        JPanel bottomBar = new JPanel();
        trainImage = new ImageIcon();
        JLabel imageLabel = new JLabel(this.trainImage);

        bottomBar.setLayout(new GridLayout(1,2,5,5));
        bottomBar.add(trainBtn);
        bottomBar.add(otp);
        this.frame.getContentPane().add(BorderLayout.CENTER,imageLabel);
        this.frame.getContentPane().add(BorderLayout.SOUTH, bottomBar);
        SwingUtilities.updateComponentTreeUI(this.frame);

        ActionListener trainListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == trainBtn) {
                    train();
                }
            }
        };

        trainBtn.addActionListener(trainListener);
    }

    void train() {
        BufferedImage bImage;
        //all 60000 numbers are extracted from a .csv file
        //i omitted everything from this function because it's not important for this question
                ...

                //this line is run 60000 times. it displays the converted pixel data (very fast) the code definitely works, it simply won't update.
                this.trainImage.setImage(bImage);
                SwingUtilities.updateComponentTreeUI(frame);
            }
        }


    }

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

Когда я нажимаю кнопку "train", графический интерфейс останавливается и не отвечает до тех пор, пока не будет выполнен метод train ()..

Ответы [ 2 ]

0 голосов
/ 19 сентября 2019

Ваш графический интерфейс завис, потому что вы выполняете много манипуляций с изображениями в потоке событий Swing.Возможно ли вам использовать что-то вроде SwingWorker?Таким образом, вы можете создать образ в отдельном потоке и обновлять графический интерфейс только при необходимости.

private void train() {
    SwingWorker<BufferedImage, Object> worker = new SwingWorker<BufferedImage, Void>() {
        @Override
        protected BufferedImage doInBackground() throws Exception {
            // load the CSV file
            BufferedImage bImage = new BufferedImage();
            // ... fill up the bImage
            return bImage;
        }

        @Override
        protected void done() {
            try {
                BufferedImage img = get();
                // ... set the trainImage
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    };

    worker.execute();
}
0 голосов
/ 19 сентября 2019

Вместо обновления trainImage, установите новый ImageIcon на JLabel

imageLabel.setIcon(new ImageIcon(bImage));

Вам также может понадобиться вызвать revalidate и / или repaint на метке для запускановый макет / проход для рисования.

Лично я бы вернул BufferedImage из метода train, поскольку метод train действительно не должен обновлять пользовательский интерфейс, это не его работа.

Когда я нажимаю кнопку "поезд", графический интерфейс останавливается и не отвечает до тех пор, пока не будет выполнен метод train ().

Да, именно поэтому Swing, как и большинство пользовательских интерфейсовИнструментарий, однопоточный.Это означает, что если вы выполняете какие-либо блокирующие или длительные операции в контексте потока диспетчеризации событий, это не позволит ему обновлять пользовательский интерфейс или реагировать на любые пользовательские входные данные.

См. Параллельность в Swing для более подробной информации.

"A" возможным решением будет использование SwingWorker.Это позволяет вам выполнить операцию блокировки / длительного запуска в другом потоке, но предоставляет несколько способов безопасной синхронизации обновлений обратно с пользовательским интерфейсом (Swing также не является поточно-безопасным;))

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

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