I have a.csv file that is full pixel data from 60000 hand-drawn digits (the mnist dataset of hand-written numbers). A function called train() is called when a button is pushed. From within the train() function, I would like each of the 60000 digits to be displayed on the screen. The code works perfectly fine, I just can't get the JFrame to update from within the train() method.
I tested the code and it 100% works as intended. I just can't get the JFrame to update while in the train() function.
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();
}
}
When I press the "train" button, the GUI freezes and is unresponsive until the train() method is done.
Rather then updating trainImage
, set a new ImageIcon
to the JLabel
imageLabel.setIcon(new ImageIcon(bImage));
You may also need to call revalidate
and/or repaint
on the label to trigger a new layout/paint pass.
Personally, I would return the BufferedImage
from the train
method, as the train
method really shouldn't be updating the UI, that's not it's job.
When I press the "train" button, the GUI freezes and is unresponsive until the train() method is done.
Yep, that's because Swing, like most UI toolkits, is single threaded. This means if you perform any blocking or long running operations within the context of the Event Dispatching Thread, it will prevent it from updating the UI or responding to any user input.
See Concurrency in Swing for more details.
"A" possible solution would be to use a SwingWorker
. This allows you to execute the blocking/long running operation on a different thread, but provides a number of ways to sync the updates back to the UI safely (Swing is also not thread safe;))
See Worker Threads and SwingWorker for more details
Your GUI is hanging because you are doing a lot of image manipulation on the Swing event thread. Is it possible for you to use something like a SwingWorker? This way you can build the image on a separate thread and only update the GUI when necessary.
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();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.