Thursday, December 23, 2010

Creating a SWT Shell that can be opened from another Java Class using WindowBuilder

WindowBuilder (sometimes called WindowBuilder Pro) is an excellent add-on for Eclipse that allows you to visually build GUIs using SWT, Swing, and a variety of other frameworks including GWT. Google acquired Insantiations, the company that made WindowBuilder, in August of 2010 and recently announced that they are donating the source code and IP of the WindowBuilder project to the Eclipse Foundation. This will likely make WindowBuilder the standard visual GUI creator for those that use Java in the Eclipse IDE.

OK, now you know a little bit about the project. You may have discovered that when using the WindowBuilder wizard to create a new shell, the wizard always creates a shell with a main method. This is very useful for quick, one screen projects, but not for projects that require more than one window.

So, do you want to create a Shell that can be called from inside another class (say, in response to a button click)?

Here are the steps that I used to accomplish the task.



  • Use the SWT WindowBuilder Wizard to make a new shell, name it anything you want (NotMain, in the following case) modify the given code as such:



  • Remove from the main method:

Display display = Display.getDefault();
        Test shell = new Test(display);

  • Cut this code out from the main method:

try {
        shell.open();
        shell.layout();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

  • Change it to:

try
        {
            open();
            layout();
            while (!isDisposed()) 
            {
                if (!display.readAndDispatch()) 
                {
                    display.sleep();
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

  • Place that code directly after

createContents();
in
public NotMain(Display display)
.

  •  Then, completely remove the main method. You should then be able to make all further modifications in the WindowBuilder "Design" window. You can remove the try/catch block, if you feel like it.


You’ll end up with something like this:
import org.eclipse.swt.SWT;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Shell;
    
    public class NotMain extends Shell 
    {
    
        /**
         * Create the shell.
         * @param display
         */
        public NotMain(Display display) 
        {
            super(display, SWT.SHELL_TRIM);
            createContents();
            try
            {
                open();
                layout();
                while (!isDisposed()) 
                {
                    if (!display.readAndDispatch()) 
                    {
                        display.sleep();
                    }
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
    
        }
    
        /**
         * Create contents of the shell.
         */
        protected void createContents() 
        {
            setText("SWT Application");
            setSize(450, 300);
    
        }
    
        @Override
        protected void checkSubclass() 
        {
            // Disable the check that prevents subclassing of SWT components
        }
    
    }

Then, to call this shell from inside of a different class, write:
btn.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                new NotMain(getDisplay());
             }
        });
(where btn is the name of your SWT button)

To change the shell to be application modal to the calling class, change your superclass call in your new shell from:
super(display, SWT.SHELL_TRIM);
to:
super(display, SWT.APPLICATION_MODAL |SWT.SHELL_TRIM);


There you go. Now, get coding!