2

My program consists of a simple gui and a class that extends thread!

i am trying to learn how to use SwingUtilities.invokeLater() in order to use it to update a textfield in my GUI but how do i reach the textfield in my gui without making static? and am i on the right track or have i done something wrong so far:)?

Code

This has been taken from the Class called Client that extends thread this is where i want to update my GUI from using SwingUtilities.invokeLater(Runnable)

public void run(){
    while (socket.isConnected()) {

    if (input.hasNext()) {

        updateTextField();
    }

}
}

private void updateTextField() {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
  // here i want to update my textfield using txt.setText(input.nextLine());

        }
    });

}

UPDATE (This is my code so far) getting a nullpointer execption

public void run(){
    while (socket.isConnected()) {
            String x = input.next();
            System.out.println(x);
    mg.updateChat(x); // this is the line that gives me the nullexeption

    }
}

in my GUI

public void updateChat(final String input){
SwingUtilities.invokeLater(new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
    txtChat.setText(input); 
    }
}); 
}
Marc Rasmussen
  • 19,771
  • 79
  • 203
  • 364
  • Please indicate by a comment in the code which line is throwing the NPE. Again, my guess is that it's being caused by the mg variable and that your line `mg.updateChat(x)` is throwing the NPE, but please prove me right or wrong. – Hovercraft Full Of Eels Oct 19 '12 at 14:44
  • How would i change mg to be my current gui? i currently intilize it by the following code: private MainGui mg; – Marc Rasmussen Oct 19 '12 at 14:47

4 Answers4

2

You can do it by having a final local variable in the method that contains the call to invokeLater(). You can access that variable from within the runnable object.

For example:

public void run(){
  while (socket.isConnected()) {
    if (input.hasNext()) {
      String nextInput = input.next();
      myGui.updateTextField(nextInput);
    }
  }
}

in your GUI class:

public void updateTextField(final String nextInput) {
  SwingUtilities.invokeLater(
    new Runnable(){
      @Override
      public void run() {
        // assuming a private JTextField variable, myTextField
        myTextField.setText(nextInput);
      }
    }
  );
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Tobias Ritzau
  • 3,327
  • 2
  • 18
  • 29
  • This gives me a nullpointerexecption. even though i know that it recives an input – Marc Rasmussen Oct 19 '12 at 14:28
  • @Marc: then you will need to debug the NPE. Consider editing your original post to show us what you've tried, and to indicate by comment which line throws the NPE (NullPointerException) since a variable on that line has not been initialized, and your code may tell us why. – Hovercraft Full Of Eels Oct 19 '12 at 14:30
  • @Marc: my guess is that your myGui field or its equivalent is null due to its not being initialized to refer to the active displayed GUI. – Hovercraft Full Of Eels Oct 19 '12 at 14:38
1

The textfields must either be declared as instance variables in the Client class or if they are declared in another class, they must be accessible from the Client class.

You are on the right track on using SwingUtilities.invokeLater(), just update the textfields inside the run() method of the Runnable inside the invokeLater.

Dan D.
  • 32,246
  • 5
  • 63
  • 79
  • I am really happy for your response and i have altered my code so the textArea is now static however now it seems that my program actually freezes when it recives my message (i think this may be because its waiting for a new input) is there any way that i can make in unfreeze? – Marc Rasmussen Oct 19 '12 at 13:56
  • 1
    It should not do that. Show us more code such as we understand what exactly you do there. – Dan D. Oct 19 '12 at 13:57
  • @marc: whatever you do, **do not** make the Swing component static. That is most definitely the **wrong** way to solve this, and I cannot stress this strongly enough! Instead make the Swing component a private class field, and use public methods to allow other classes to interact with it, just as you would any other Swing field or property. – Hovercraft Full Of Eels Oct 19 '12 at 14:07
1

Regarding your NPE:

public void run() {
  while (socket.isConnected()) {
    String x = input.next();
    System.out.println(x);
    mg.updateChat(x); // this is the line that gives me the nullexeption
  }
}

This means that mg must be null, and the reason for this is that you haven't given this variable a valid reference to the GUI. To solve this, you need to pass in a reference to the displayed GUI via either a method or constructor parameter. For instance, if via a constructor, you could do:

public class MySocketConnector implements Runnable {
  private MainGui mg;

  public MySocketConnector(MainGui mg) {
    this.mg = mg;
  }

  @Override
  public void run() {
    while (socket.isConnected() {
      // ... etc...
    }
  }

  //...
}

Edit 1
Regarding your comment:

How would i change mg to be my current gui? i currently intilize it by the following code: private MainGui mg;

This just declares the variable but it doesn't initialize it.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Okay so a good rule of thumbs would be whenever i need something in my class from another class i need to pass it into the constructor? but wouldnt this make the coding very spaghetti like? – Marc Rasmussen Oct 19 '12 at 14:54
  • @Marc: nope, it shouldn't be spaghetti like if done well and correctly, and no, you don't always pass these things in the constructor. Sometimes you'll use a setter method for this. – Hovercraft Full Of Eels Oct 19 '12 at 14:55
  • Mate you have no idea how much and all of the other comments has helped me! you just learned me something that i have been wondering about for over a week! btw i ended up declaring the mg in the mainGui like this: private MainGui mg = MainGui.this; - Also this stopped the program from freezing! :) and then added it in the constructor :) – Marc Rasmussen Oct 19 '12 at 15:00
  • @Marc: glad you've got things working, but I don't think that you need to declare a MainGui variable inside of the MainGui class. Simply passing `this` into the Socket class's constructor (if being constructed inside of MainGui) should be enough. – Hovercraft Full Of Eels Oct 19 '12 at 15:13
0

One thing you can do is have a String field in your class that extends Thread class. And inside run() method set that field to whatever value you want in your textfield. And then write a method that returns the string that you set inside run() and call that method to set your textfield.

Abubakkar
  • 15,488
  • 8
  • 55
  • 83