Blueraaga
Blueraaga

Reputation: 93

JLabel changing values through setText but not updating on screen

Well, I have been working on a piece of code for almost 2 days now and not able to resolve the issue.

DESIRED BEHAVIOUR

The following code is supposed to display 10 strings one by one (the next replacing the previous one) with a gap of aprox. 200 ms.

q1 q2 q3 ...and so on upto q10

This display sequence starts when the user presses ENTER key.

REFLECTED BEHAVIOUR

The screen waits for aprox. 2 sec after pressing and then shows q10.

Some more info

  1. The label stringText changes value during execution (which I found by writing to console) but the same is not updated on screen (JFrame).
  2. The label changes values through click event on a button, everything else remaining same (as much as possible).
  3. The timer is through a while loop - this may not be as per most people's liking, but lets forget it for the time being.
  4. The method displayQuestion(int number) has a few unnecessary lines. I put them all because I was not sure what would work. Actually, nothing worked!

THE CODE

package sush4;

import java.util.Date;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Sush4 {

    // Timer control variables
    static long holdTimeWord = 200L;
    static long elapsedTime = 0L;

    // Counter for Strings displayed
    static int i = 0;

    // Strings in use
    static String[] questionStack = {"q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10"};

    // UI: String display variables
    static JLabel stringText;
    static JFrame mainWindow;

    // Key binding action object
    private static Action userKeyCommand;

    /// Display the question
    private static void displayQuestion(int number) {
        mainWindow.remove(stringText);
        stringText.setText(questionStack[number]);
        mainWindow.add(stringText);
        mainWindow.setVisible(true);
        mainWindow.revalidate();
        mainWindow.repaint();
    }

    private static void q120(){

        //// Initiate the text
        for(i = 0; i < questionStack.length; i++) {

            displayQuestion(i);

            //// And wait for Word hold time
            long startTime = System.currentTimeMillis();
            elapsedTime = 0L;
            // Now wait for event to happen
            while ( (elapsedTime < holdTimeWord) ) {
                elapsedTime = (new Date()).getTime() - startTime;
            }
        }
    }

    Sush4() {

        //// Create the Window
        mainWindow = new JFrame("Sush");
        mainWindow.setSize(700, 500);
        mainWindow.setLayout(new FlowLayout());

        //// And add key bindings for user events
        userKeyCommand = new UserKeyCommand();
        JRootPane rootPane = mainWindow.getRootPane();
        rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ENTER"), "doEnterAction");
        rootPane.getActionMap().put("doEnterAction", userKeyCommand);

        // Terminate the program when the user closes the application.
        mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainWindow.setResizable(false);

        //// Add the text label
        stringText = new JLabel("Random Text");
        mainWindow.add(stringText);

        //// Finally, display the frame.
        mainWindow.setVisible(true);
    }

    static class UserKeyCommand extends AbstractAction {
        public void actionPerformed( ActionEvent tf ) {
            q120();
        } 
    } 

    public static void main(String[] args) {

        // Create the frame on the event dispatching thread.
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Sush4();
            }
        });
    }
}

Upvotes: 2

Views: 697

Answers (1)

dic19
dic19

Reputation: 17971

The timer is through a while loop - this may not be as per most people's liking, but lets forget it for the time being.

Actually we can't forget about this while loop because this is what is causing troubles. See, q120() method is called when you click a button:

static class UserKeyCommand extends AbstractAction {
    @Override // don't forget @Override annotation
    public void actionPerformed( ActionEvent tf ) {
        q120();
    } 
} 

It means this code is executed in the context of the Event Dispatch Thread (EDT). This is a single and special thread where Swing components must be created/updated and event handling (i.e.: action events) must be performed. If we have a loop in this thread waiting for some condition to continue we'll block the EDT and GUI won't be able to repaint itself until the thread is unlocked.

For repetitive tasks (such as the one in your question) consider use a Swing Timer. For heavy tasks with interim results consider use a SwingWorker instead.

Upvotes: 4

Related Questions