Showing posts with label Eclipse. Show all posts
Showing posts with label Eclipse. Show all posts

Thursday, December 24, 2009

Nightmare before Christmas: How to use JFace + SWT standalone

I could've as easily called this Eclipse plugins from HELL, but being Christmas and all I thought I would go for the Christmas thing, which gives me the opportunity to wish Merry Xmas to all the geeks who happen to be reading this lame-ass blog over the holidays instead of watching Star Trek as per tradition.

Being mainly a .NET guy, I am not too familiar with the eclipse platform, but I desperately needed to put together a quick UI and decided to go with JFace and SWT after @tarelli suggested so (he's the JAVA guy). Unfortunately, at the time I didn't realize he was talking about an Eclipse plugin project and not about using JFace and SWT in a standalone Java app.

So I went on and got started with some nice tutorials specific to running JFace + SWT standalone, and some more gentle introductions.

Time to get my hands dirty, so I started a new Java project, and dropped in some of the code from the tutorials. In order to get it build I needed to import JFace and SWT plugins as external jars, which I could not find anywhere in my plugins folder (I am on Galileo C:\eclipse 3.5\plugins). I needed to somehow get the damn plugins, but could not quite figure out how to get only those I needed from Help --> Install Software Updates, so I ended up pulling down anything to do with Eclipse SDK. To my delight the SWT and JFace plugins were there (in the plugins folder) after the lengthy process of downloading tons of stuff I didn't need.

After a bit of mocking about (blindly trying to import anything with jface or swt in it) I managed to understand which jars I needed to import to get the damn thing to build (org.eclipse.jface_3.5.1.M20090826-0800.jar and org.eclipse.swt.win32.win32.x86_3.5.1.v3555a.jar) I started mocking about with the code and spent a good while playing around with ContentProviders, ListViewers and so forth. Everything was building nicely, but as soon as I tried to run it as java application got the cold shower:

Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/core/runtime/IProgressMonitor
    at demo.ui.test.EntryPoint.main(EntryPoint.java:18)
Caused by: java.lang.ClassNotFoundException: org.eclipse.core.runtime.IProgressMonitor

Apparently some type was missing somewhere. I've seen a lot of sh*t working on Visual Studio and all, but errors don't get much more cryptic than this.

After a good while, after unfruitfully trying to offline troubleshoot the heck out of my project (offline troubleshooting is just madness but I was waiting the phone company to turn on my broadband in the new apt i moved to recently), I reverted to @tarelli, the eclipse guru who got me into this mess, and begged for help: he promptly told me that I was in a bit of a feckin' mess, and if I wanted to get out of it alive I would've had to create a Plugin Project "with a view" and take it from there. I tried, and he was right, but I did not want a plugin and all the overhead that comes with it, so I kept pulling my hair for several hours with no luck, then went to bed. I felt rightly and truely screwed, if you want.

Luckily the day after the phone company turned on my broadband and I could stop passively obsessing about the problem and started aggressively abusing google in search of a solution to the problem.

After a not too long research (God bless THE INTERNET), turns out that if you want to use JFace + SWT outside a plugin based project you need some other jars. Basically if you're using JFace and SWT in a plugin project runtime dependencies are managed for you through the manifest file (I seem to understand) but if you go for the rogue option of having SWT running standalone then you need to know you need that stuff.

In the specific case of the IProgressMonitor thingy, adding a reference to the org.eclipse.equinox.common jar did the trick. After that I got the same error on a different class, EventManager, and after a couple of blind trials I got it working by importing the org.eclipse.core.commands jar. Obviously, not a mention of this in the tutorials, as I seem to understand there was a bit of refactoring on those packages after those tutorials were drafted (looks like this problem is around since eclipse 3.2 --> read this bug report for further info).

What can I say? If you're coming from .NET sometimes Java == Pain.

Wednesday, April 23, 2008

[Java, SWT] Invalid thread access


Problem: You have your own GUI made with Eclipse SWT, you try to update a widget from within an external thread, and you obtain the exception:
org.eclipse.swt.SWTException: Invalid thread access

Solution: SWT is not thread safe, meaning that if you try to modify a widget from a thread you previously runned external from the one that contains the GUI, the JVM ends the application. Actually Swing is neither thread safe, but you won't receive an exception (and your application behaves in an unpredictable way).

Obviously there is a way to handle this problem, using the .asyncExec(Runnable r) or .syncExec(Runnable r) methods of the Display SWT class: passing a valid implementation of a Runnable class, SWT will allow GUI accesses as soon as possibile. This code is a way of using this pattern:

public class MyGUIClass{

private Display _display = null;

public static void main(String[] args)
{
/* main thread */
final Display display = new Display();
/* this allows a future catch of this class */
_display = display;
final Shell shell = new Shell(display);
final Button button = new Button(shell,SWT.PUSH);
button.setText("Run a thread");
button.addSelectionListener(new SelectionListener()
{
public void widgetSelected(SelectionEvent e) {
/* this class starts a new thread */
MyComputationClass mcc = new MyComputationClass ();
mcc.createNewThread(this);
}

public void widgetDefaultSelected(SelectionEvent e) {}
});
}

/* this main class exposes a public method that returns the
current Display class
*/
public Display getDisplay()
{
return _display;
}

The MyComputationClass in the .createNewThread(MyGUIClass aGUI) will try to update the GUI (from a separate thread). Inside the thread this is the correct code to make SWT dispatch your code:

public class MyComputationClass{
public void createNewThread(MyGUIClass aGUI)

/* a new thread is running */
/* make intensive computation . . .*/
/* . . . */
if(!aGUI.getDisplay().isDisposed()){
aGUI.getDisplay().asyncExec (new Runnable ()
{
public void run () {
aGUI.doSomeGUIModifications();
}
});

/* . . . */
/* thread is ended up */
}
}

This comes from a process of butchering my own Java GUI, so I'm not sure if it is the only way to do it. Anyway, like my dear old friend Giovacchia uses to say, "Don't try to be a perfect coder, just be a perfect butcher!".
See ya!