Search code examples
javamultithreadingswingjframejtextpane

Thread JFrame needs to update JTextPane


I have following code. I need to update JTextPane object when result variable changes. Result variable changes properly, it's tested. This code works as thread. I really doesn't have idea how to solve it, maybe any eventlistener would be good there?

public class GeneralShopFrame implements Runnable, Observer{
    private double result = 0 ;
    JFrame jf = new JFrame();
    JPanel buttonPanel = new JPanel();
    JTextPane jtp = new JTextPane();
    @Override
    public void run() {   
        String[] tab = { "Data_0.txt", "0" } ;
        GeneralShopThread gst = new GeneralShopThread(tab);
        Runnable r = gst;
        Thread t = new Thread(r);
        t.start();

        GeneralShopFrame gsf = new GeneralShopFrame();
        gst.addObserver(gsf);       

        jtp.setText("Current value of result is " + result);  //I NEED UPDATE IT

        buttonPanel.add(jtp); 

        buttonPanel.setPreferredSize(new Dimension(400, 200));

        jf.add(buttonPanel, BorderLayout.CENTER);
        jf.pack();
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
    }

    public GeneralShopFrame(String[] args) {
    }    

    @Override
    public void update(Observable o, Object arg) {

        result = (double) arg;
        System.out.println(makespan);    
    }
}

Solution

  • You should call setText(...) on the JTextPane from within the update method, taking care to be sure that it is called on the Swing event thread, e.g., from within a Runnable that is queued on the event thread using SwingUtilities.invokeLater(...). e.g.,

    // code not tested
    @Override
    public void update(Observable o, Object arg) {
        SwingUtilities.invokeLater(() -> {
            result = (double) arg;
            jtp.setText("Current value of result is " + result);
        });
    }
    

    But you state that it doesn't work, and your code shows why: you're creating another GeneralShopFrame object within your run method above, one that is not displayed, and because of this, you're notifying the wrong GeneralShopFrame object of changes to an observable. Don't do this. Instead perhaps pass the current GeneralShopFrame object or this into this call:

    gst.addObserver(this);