javaswingactionlistenerrepaint

Refreshing a JFrame while in an Action Listener


The code snippet below sets text in a JLabel, which is added to a JPanel, which is attached to a JFrame. No matter what I do though (such as repaint(), revalidate(), etc) I cannot get the UI to update the text until the Action Listener is done.

I have never had this problem before, possible because I have never had to have several things happen in a single firing of Action Listener. What am I missing?

TL;DR Why does the following not update the text on the screen until it has finished firing the Action Listener, even if I put in repaint() after each listPanel.add()?

final JFrame guiFrame = new JFrame();
final JPanel listPanel = new JPanel();
listPanel.setVisible(true);
final JLabel listLbl = new JLabel("Welcome");
listPanel.add(listLbl);

startStopButton.addActionListener(new ActionListener(){@Override public void         actionPerformed(ActionEvent event){
     if(startStopButton.getText()=="Start"){
                startStopButton.setVisible(false);
                listPanel.remove(0);

     JLabel listLbl2 = new JLabel("Could not contact”);
                listPanel.add(listLbl2);

     JLabel listLbl2 = new JLabel("Success”);
                listPanel.add(listLbl2);
     }
}
guiFrame.setResizable(false);
guiFrame.add(listPanel, BorderLayout.LINE_START);
guiFrame.add(startStopButton, BorderLayout.PAGE_END);

//make sure the JFrame is visible
guiFrame.setVisible(true);

EDIT: I attempted to implement SwingWorker, but still the interface is not updating until the action interface finishes firing. Here is my SwingWorker code:

@Override
protected Integer doInBackground() throws Exception{
    //Downloads and unzips the first video.  
    if(cameraBoolean==true)
        panel.add(this.downloadRecording(camera, recording));
    else
        panel.add(new JLabel("Could not contact camera "+camera.getName()));

    panel.repaint();
    jframe.repaint();
    return 1;
}

private JLabel downloadRecording(Camera camera, Recording recording){
    //does a bunch of calculations and returns a jLabel, and works correctly
}

protected void done(){
    try{
        Date currentTime = new Timestamp(Calendar.getInstance().getTime().getTime());
        JOptionPane.showMessageDialog(jframe, "Camera "+camera.getName()+" finished downloading at "+currentTime.getTime());
    }catch (Exception e){
        e.printStackTrace();
    }
}

Basically, SwingWorker (as I implemented it) is not properly updating the JPanel and JFrame. If I try to do the repaint in the "done()", they are not updated either. What am I missing?

Additionally, as soon as the JOptionPane displays itself, no more panels can be added to my jframe. I am unsure what is causing that either.


Solution

  • The action listener is being executed on the Event Dispatch Thread. For tasks like that, consider using a SwingWorker.

    This would allow you to process your logic without blocking the updates (and thus the repaints) of the JFrame.

    At a high level, this is what I mean:

    startStopButton.addActionListener(new ActionListener(){@Override public void         actionPerformed(ActionEvent event){
         if(startStopButton.getText()=="Start"){
              // Start SwingWorker to perform whatever is supposed to happen here.
         }
    

    You can find some information on how to use SwingWorker here, should you need it.