-1

Please look at the code below.

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;

class thread_jishu extends Thread{
    @Override
    public void run(){
        int p=-1;
        for(;;){
            //here continuously checking that whether
            //the value of label_thread.i is equals to p or not

            if(label_thread.i!=p){
                try{
                    Thread.sleep(1000);
                }catch(Exception e){}

                label_thread.lb.setText("after sleeping at -> "+label_thread.i);
                // here i want to set the JLabel
                // text after waiting 1sec only when
                // label_thread.i has been changed,
                // but not happening 
                p=label_thread.i;
            }
        }
    }
}

public class label_thread  implements java.awt.event.ActionListener{

    /**
     * @param evt
     */
    @Override
    public void actionPerformed(java.awt.event.ActionEvent evt){
        i+=1;
        lb.setText("Button clicked at -> "+i);
    }

    static int i=-1;
    static JLabel lb=new JLabel("hello here");
    static JFrame window=new JFrame("Jishu");
    static JFrame window2=new JFrame("Jishu");

    public static void main(String[] args) {
        // TODO code application logic here
        new thread_jishu().start();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setMinimumSize(new java.awt.Dimension(200,200));

        JButton bt=new JButton("Click here");
        bt.addActionListener(new label_thread());
        JPanel panel=new JPanel();
        panel.add(bt);
        window.add(panel);
        window2.add(lb);
        window.setVisible(true);
        window2.setVisible(true);
        window2.setMinimumSize(new java.awt.Dimension(200,200));
    }

}

I want to reset the JLabel in the 2nd window when the value of i is not equals to p that means the button is clicked in 1st window.

But when button is clicked JLabel's text is not being changed.

basgys
  • 4,320
  • 28
  • 39
ANUPAM
  • 53
  • 2
  • 3
  • 11
  • This might happen because of concurreny in the project as the same variable is used. Try and make variable i as volatile in label_thread class – Vivek Singh Oct 23 '15 at 19:15
  • 3
    Swing components may only be modified in the AWT event dispatch thread. Modifying them in any other thread will result in unpredictable behavior. Also, variables accessed from multiple threads, like `label_thread.i`, need to be marked `volatile`. (And your try/catch should be around your loop, not inside it.) – VGR Oct 23 '15 at 19:26

2 Answers2

0

Swing elements should not be modified outside of the AWT event thread. You can use SwingUtilities.invokeLater if you'd like to execute code in the AWT event thread.

Something like:

SwingUtilities.invokeLater(new Runnable() {
    @override
    public void run() {
        //Swing stuff here.
    }
});

would get you pretty close.

Chase Henslee
  • 3,918
  • 1
  • 18
  • 21
0

There are a number of potential issues;

  • Overuse/reliance on static
  • Swing thread violations
  • Thread memory access of variables
  • And general poor design.

static is not helpful and can cause all sorts of issues in the long run. static is not a cross object communication mechanism and you should learn other techniques for dealing without it

Swing is single threaded framework and it is not thread safe, this basically means that you should not perform long running tasks within the context of the Event Dispatching Thread and you should also not modify the state of the UI from outside the context of the EDT (like setting the text of the label from another thread).

Accessing variables from within Threads and be problematic, as the Thread can get it's own copy of the variable, this means that reads and writes to the variable can be delayed between threads, meaning that they may not see the latest value. Typically, you can resolve this with the volatile keyword or using the atomic API, like AtomicInteger, but I think with a little better design, you can avoid these needs.

Now, you could use a SwingWorker or a Swing Timer, both of which provide solutions to controlling updates to the EDT in a save way, but you also still use a thread.

You program is suffering from basic poor design, you're expose a bunch of properties to uncontrolled modifications and access, making it difficult to resolve the responsibilities of the classes (who can do what and when).

So, to start with, I'm going to define some control

public interface Counter {
    public int getCount();
    public void setText(String text);
}

This simple interface provides access to the current count value and provides a means for another class to set the text of the implementation. This defines the "contract". This means that who ever I pass an instance of this interface to, they can only perform those two tasks and it's up to the implementation to decide how those actions are controlled

Next, I setup the Thread....

public class ThreadJishu implements Runnable {

    private Counter counter;
    private int initialCount;

    public ThreadJishu(Counter counter) {
        this.counter = counter;
    }
    
    @Override
    public void run() {
        this.initialCount = counter.getCount();
        while (true) {
            if (counter.getCount() !=  initialCount) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                }
                initialCount = counter.getCount();
                counter.setText("After sleep at -> " + initialCount);
            }
            Thread.yield();
        }
    }
}

So, this isn't that different from what you were doing, except, I'm relying on the implementation of Counter to do the work I need it to do.

And finally, the implementation of Counter, the CounterPane

public class CounterPane extends JPanel implements Counter {

    private int count = 0;
    private JLabel label;
    
    public CounterPane() {
        
        label = new JLabel("Hello");
        JButton btn = new JButton("Click here");
        
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        
        add(label, gbc);
        add(btn, gbc);
        
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count++;
                setText("Button click count = " + count);
            }
        });
        
        Thread t = new Thread(new ThreadJishu(this));
        t.start();
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void setText(String text) {
        if (EventQueue.isDispatchThread()) {
            label.setText(text);
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    setText(text);
                }
            });
        }
    }

}

This provides the interface to the user as well as defines the workings of the Counter. In the setText method, we have a safe guard which ensures that all modifications to the JLabel are done from within the context of the EDT and for simplicity, the JButton's ActionListener actually uses the setText method as well.

Runnable example...

Click Me

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class LabelThread {

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

    public LabelThread() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new CounterPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Counter {
        public int getCount();
        public void setText(String text);
    }

    public class CounterPane extends JPanel implements Counter {

        private int count = 0;
        private JLabel label;

        public CounterPane() {

            label = new JLabel("Hello");
            JButton btn = new JButton("Click here");

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            add(label, gbc);
            add(btn, gbc);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    count++;
                    setText("Button click count = " + count);
                }
            });

            Thread t = new Thread(new ThreadJishu(this));
            t.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        public int getCount() {
            return count;
        }

        @Override
        public void setText(String text) {
            if (EventQueue.isDispatchThread()) {
                label.setText(text);
            } else {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        setText(text);
                    }
                });
            }
        }

    }

    public class ThreadJishu implements Runnable {

        private Counter counter;
        private int initialCount;

        public ThreadJishu(Counter counter) {
            this.counter = counter;
        }



        @Override
        public void run() {
            this.initialCount = counter.getCount();
            while (true) {
                if (counter.getCount() !=  initialCount) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                    }
                    initialCount = counter.getCount();
                    counter.setText("After sleep at -> " + initialCount);
                }
                Thread.yield();
            }
        }
    }

}

Concurrency is a complex subject to begin with, made more complicated by the needs of the Swing API (like most GUI APIs).

Have a look at:

for more details and possible solutions for common problems

Swing Timer example...

And a simple implementation using a Swing Timer, no Thread's required

public class CounterPane extends JPanel implements Counter {

    private int count = 0;
    private JLabel label;

    private Timer timer;

    public CounterPane() {

        label = new JLabel("Hello");
        JButton btn = new JButton("Click here");

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;

        add(label, gbc);
        add(btn, gbc);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count++;
                setText("Button click count = " + count);
                timer.restart();
            }
        });

        timer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setText("After sleep at -> " + getCount());
            }
        });
        timer.setRepeats(false);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void setText(String text) {
        label.setText(text);
    }

}
Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366