Showing posts with label SWT. Show all posts
Showing posts with label SWT. 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!

Tuesday, April 1, 2008

[Java] Introducing GUI with Swing and SWT

These days I'm having a look at JAVA GUIs, playing with different 2D libraries: AWT, JFC/Swing, SWT and JFace.
Actually AWT is the base library for 2D issues and lacks of several common controls (see figure, taken from here).

To fulfill those lacks, the JRE comes with the Java Foundation Classes (JFC) / Swing libraries, with all kind of controls, allowing the creation of complex GUIs.
If anyway you are looking for something quick to implement, you should use the SWT (Standard Widget Toolkit) library, based upon Swing and AWT, created by IBM as the graphic constituent for Eclipse Framework (actually over SWT lies JFace, a graphic library created to support common programming features, not treated in this post).
In Swing controls are disposed automatically by the garbage collector, while in SWT you have manually to dispose them, like in the current example in which a simple window with a lable is created:
SWING

import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class SwingHelloWorld extends JFrame {

public static void main(String args[]) {
new SwingHelloWorld();
}
SwingHelloWorld() {
JLabel jlbHelloWorld = new JLabel("Just a label");
add(jlbHelloWorld);
setTitle("Example Frame");
setLayout(new GridLayout());
this.setSize(300, 100);
setVisible(true);
}
}

SWT

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class SWTHelloWorld {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("Example Frame");
shell.setSize(300,100);
shell.setLayout(new GridLayout());

/* controls code goes here */
Label label1 = new Label(shell, SWT.BORDER);
label1.setText("Just a label");
label1.setSize(100,20);

shell.open();
while(!shell.isDisposed())
{
if(!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
}

As seen in Swing the main class is inherited straight from the JFrame Swing class, while in the SWT version there is the Display object that is a repository of display OS-dependent features and a Shell which is the actual window: you can have several shells for one display. Moreover in the SWT code there is a while loop, which waits for the disposal of the shell (done by the close button [X]) and in that case the main class disposes the Display instance (actually the disposal of all objects is done automatically by the container's dispose event, i.e. by the disposal of the shell).

Another difference between the two libraries is the graphical look:


SwingSWT





It is clear that SWT library depends on the OS look (thanks to the Display object), while Swing uses typical JAVA interface.

If you are planning to learn basics of JAVA GUIs, try first with Swing and than switch to SWT, so you'll gain a wide view of those technologies and learn for each application the one which suites your needs.

Hope JohnnyIdol learned something... he just got served.

Stay tuned!