KessEkhtak
KessEkhtak

Reputation: 55

Java swing how to open frame in another thread

My custom JFrame implements runnable interface, so it contains the run method, and in my main method, this is how I try to open my frame:

public static void main(String[] args) {

      new Thread() {
          @Override
          public void run() {
              Cadre cadre = new Cadre();
          }
      }.start();
}

Unfortunately this done not make the frame appear, it seems to ignore the frame's run method.

and here's my class:

public class Cadre extends JFrame implements Runnable {
    private PanneauHaut panneauHaut;
    private PanneauBas panneauBas;

    @Override
    public void run() {
        System.out.println("Thread started"); 
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        this.panneauHaut = new PanneauHaut();
        this.panneauBas = new PanneauBas();
        JPanel mainPanel = new JPanel();
        JTextField kooltxt = new JTextField("hehehe");
        mainPanel.setLayout(new BorderLayout());
        mainPanel.add(panneauHaut, BorderLayout.NORTH);
        mainPanel.add(panneauBas.getPanel(), BorderLayout.SOUTH);
        this.setContentPane(mainPanel);
        this.setVisible(true);
    }
}

What could be wrong?

Upvotes: 1

Views: 1552

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

You don't and you shouldn't. Swing is single threaded AND not thread safe. Look at Concurrency in Swing for more details

The "major" problem is, you are creating a new instance Cadre in the Thread's run method, but nothing is calling the Cadres run method...

new Thread() {
    @Override
    public void run() {
        Cadre cadre = new Cadre();
    }
}.start();

Where is Cadre#run called?

A "better" solution would be to do something more like EventQueue.invokeLater(new Cadre()), which will execute the Cadre's run method within the context of the Event Dispatching Thread - safely

Nothing happens with invokeLater

Works fine for me - any additional problems are likely some where else in the code you've not provided, that or you need to do a clean and build to flush out any "stale" binaries.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

public class Test {

  public static void main(String[] args) {
    EventQueue.invokeLater(new Cadre());
  }

  public static class Cadre extends JFrame implements Runnable {

//  private PanneauHaut panneauHaut;
//  private PanneauBas panneauBas;

    @Override
    public void run() {
      System.out.println("Thread started");
      this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//    setExtendedState(JFrame.MAXIMIZED_BOTH);
//    this.panneauHaut = new PanneauHaut();
//    this.panneauBas = new PanneauBas();
      JPanel mainPanel = new JPanel();
      JTextField kooltxt = new JTextField("hehehe");
      mainPanel.setLayout(new BorderLayout());
      mainPanel.add(kooltxt);
//    mainPanel.add(panneauHaut, BorderLayout.NORTH);
//    mainPanel.add(panneauBas.getPanel(), BorderLayout.SOUTH);
      this.setContentPane(mainPanel);
      pack();
      setLocationRelativeTo(null);
      this.setVisible(true);
    }
  }

}

Upvotes: 3

John Bollinger
John Bollinger

Reputation: 180151

it seems to ignore the frame's run method

Well of course it does. You have instantiated an anonymous subclass of Thread whose run() method does nothing but instantiate a Cadre via its default constructor. Nothing there would cause the new Cadre's run() method to run.

You could instead instantiate a stock Thread() via the constructor that accepts a Runnable:

new Thread(new Cadre()).start();

... but that seems pretty pointless.

Be aware in particular that Swing itself does all its work in yet a different thread, the "Event-Dispatch Thread", and that Swing and standard Swing components are not thread-safe.

Better, then, would be

SwingUtilities.invokeAndWait(new Cadre());

(or invokeLater(new Cadre())), but that will cause the Cadre's run() method to run on the Event-Dispatch thread, not on some random other thread of your choosing. In fact, that's probably what you should do, since the method in question constructs and displays a Swing GUI, but it's not what you seem to think you want to do.

Upvotes: 1

Related Questions