powered by Jive Software

SWT + Invalid thread access

Hi all,

I’'ve started to write a SWT client which embedd Smack API.

When I try to use the presenceChanged method of the RosterListener to call an element of my SWT gui, it always crash with the same error:

org.eclipse.swt.SWTException: Invalid thread access

I’'ve search informations on forums and it seems due to SWT thread model… (http://www.eclipse.org/swt/faq.php#uithread)

Then I wonder how to manage to use smack api with SWT graphic api.

I really dont know how to do!

Thanks for your help and your replies.

e07

Well from a quick reading of the swt faq you posted it looks like you would need to perform your Roster UI update within either the

syncExec(Runnable runnable)

/code

or

asyncExec(Runnable runnable)

/code

methods.

The example given sets the Text of a JLabel.

display.syncExec(

new Runnable() {

public void run(){

label.setText(text);

}

});

/code

Perhaps if you posted the code which is failing we might be able to shed a bit more light on the subject

JonWright is right, in SWT only the main thread can access & update the UI (swt components).

With smack, the events can be executed from another thread and this is why you get this error.

syncExec blocks your program until the content is executed

asynExec execute the content in the background.

(if you have other problems with swt & smack I may be able to help you since I’'m using smack in my RCP application (SWTJFaceEclipse).)

Hi guys,

First, thanks for your fast reply…that’'s cool!

Here’‘s an example of code I’'d like to run whitout SWTerror using Smack and SWT:

package fr.elh.smack;

import java.util.Collection;

import org.eclipse.swt.SWT;

import org.eclipse.swt.graphics.Point;

import org.eclipse.swt.layout.FillLayout;

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Shell;

import org.eclipse.swt.widgets.Tree;

import org.jivesoftware.smack.Roster;

import org.jivesoftware.smack.RosterListener;

import org.jivesoftware.smack.XMPPConnection;

import org.jivesoftware.smack.XMPPException;

public class MainSwt {

private Shell sShell = null;

private Tree tree = null;

public XMPPConnection conn = null; // @jve:decl-index=0:

public Roster roster = null;

/**

  • @param args

*/

public static void main(String[] args) {

Display display = Display.getDefault();

MainSwt thisClass = new MainSwt();

thisClass.createSShell();

thisClass.sShell.open();

while (!thisClass.sShell.isDisposed()) {

if (!display.readAndDispatch())

display.sleep();

}

display.dispose();

}

/**

  • This method initializes sShell

*/

private void createSShell() {

sShell = new Shell();

sShell.setText(“Shell”);

sShell.setSize(new Point(300, 200));

sShell.setLayout(new FillLayout());

tree = new Tree(sShell, SWT.NONE);

try {

conn = new XMPPConnection(“myJabberDomain”, 5222);

conn.login(“myLogin”, “myPwd”);

} catch (XMPPException e) {

e.printStackTrace();

}

roster = conn.getRoster();

roster.addRosterListener(new RosterListener(){

public void entriesAdded(Collection arg0) {}

public void entriesUpdated(Collection arg0) {}

public void entriesDeleted(Collection arg0) {}

public void presenceChanged(String arg0) {

//this line produces the SWTError : org.eclipse.swt.SWTException: Invalid thread access

System.out.println("read SWT tree from smack thread: " + tree);[/b]

}

});

}

}

Could you help me to find the right code using threads?

Thank you very much!!

e07

Well going on from what we both said earlier,

you are trying to access an Object from the SWT Thread from outside of it, thus causing the exception.

This line here

System.out.println("read SWT tree from smack thread: " + tree);

/code

What you will need to do I presume is wrap this line up using either syncExec or asyncExec methods.

So in the RosterListener, under the presence change method you could it call a method from your Display class that is wrapped in code like below.

display.syncExec(

new Runnable() {

public void run(){

updateRoster();

}

});

/code

Message was edited by: JonWright

thx,

do you mean the right code could be stuff like that?

package fr.elh.smack;

import java.util.Collection;

import org.eclipse.swt.SWT;

import org.eclipse.swt.graphics.Point;

import org.eclipse.swt.layout.FillLayout;

import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Shell;

import org.eclipse.swt.widgets.Tree;

import org.jivesoftware.smack.Roster;

import org.jivesoftware.smack.RosterListener;

import org.jivesoftware.smack.XMPPConnection;

import org.jivesoftware.smack.XMPPException;

public class MainSwt {

private static Display display = null;

private Shell sShell = null;

private Tree tree = null;

public XMPPConnection conn = null; // @jve:decl-index=0:

public Roster roster = null;

/**

  • @param args

*/

public static void main(String[] args) {

display = Display.getDefault();

MainSwt thisClass = new MainSwt();

thisClass.createSShell();

thisClass.sShell.open();

while (!thisClass.sShell.isDisposed()) {

if (!display.readAndDispatch())

display.sleep();

}

display.dispose();

}

/**

  • This method initializes sShell

*/

private void createSShell() {

sShell = new Shell();

sShell.setText(“Shell”);

sShell.setSize(new Point(300, 200));

sShell.setLayout(new FillLayout());

tree = new Tree(sShell, SWT.NONE);

try {

conn = new XMPPConnection(“myJabberDomain”, 5222);

conn.login(“myLogin”, “myPwd”);

} catch (XMPPException e) {

e.printStackTrace();

}

roster = conn.getRoster();

roster.addRosterListener(new RosterListener(){

public void entriesAdded(Collection arg0) {}

public void entriesUpdated(Collection arg0) {}

public void entriesDeleted(Collection arg0) {}

public void presenceChanged(String arg0) {

//this line produces the SWTError : org.eclipse.swt.SWTException: Invalid thread access

display.syncExec(

new Runnable() {

public void run(){

updateRoster();

}

});

}

});

}

public void updateRoster(){

System.out.println("read SWT tree from smack thread: " + tree);

}

}

it works…

thk