Eclipse

Integrating Swing into Eclipse RCPs

_침묵_ 2006. 6. 18. 04:00

http://www.eclipsezone.com/eclipse/forums/t45697.html

Integrating Swing into Eclipse RCPs

Rich Client Applications (RCPs) typically require complex, interactive charts and other non-standard widgets. Unfortunately, there are not many open source (or even commercial) SWT charting libraries yet, so RCP developers either have to develop their own or use an existing Swing components. Fortunately, the RCP 3.x platform includes the SWT_AWT bridge, which allows RCPs to integrate Swing components (at least on Windows and Linux)

The SWT_AWT Bridge

What is the SWT_AWT Bridge and how does it work? Suppose we want to embed a Swing JPanel inside an Eclipse RCP View:

 

Composite swtAwtComponent = new Composite(parent, SWT.EMBEDDED);

java.awt.Frame frame = SWT_AWT.new_Frame( swtAwtComponent );

javax.swing.JPanel panel = new javax.swing.JPanel( );

frame.add(panel);

 

Thenew_Frame()method creates apartiallythread-safe SWT Composite container,swtAwtComponent, for the AWT or Swing component. Notice that theswtAwtComponentmust be created using the SWT.EMBEDDED style.

Disposing Components in a Thread-Safe Way

Because neither Swing now SWT is thread-safe, the RCP developer must take care not to invoke (non thread-safe) Swing methods from SWT, or vice versa. For example, we know that we (or the RCP framework) must explicitly dispose SWT components. However, to dispose our RCP View, we shouldnotnaively callframe.dispose()because the Swingdisposemethod is not thread-safe.

 

// do not do this !

public void dispose() {

  this.frame.dispose();

  super.dispose();

}

 

Doing so will cause the RCP to deadlock (try it)! You should not invoke the frame.dispose() directly from SWT because Swing is not thread-safe. The method frame.dispose() should only be invoked directly from the Swing/AWT Event Dispatch Thread and not from the SWT (RCP) main thread. To see how to invoke frame.dispose() safely, let us examine how the AWT_SWT class disposes the frame it has created. The SWT_AWT bridge listens for SWT.Dispose events, and then safely invokes the AWTdispose()method by posting a runnable to the AWT EventQueue:

 

Listener listener = new Listener () {

  public void handleEvent (Event e) {

    switch (e.type) {

      case SWT.Dispose:

        parent.setVisible(false);

        EventQueue.invokeLater(new Runnable () {

          public void run () {

            frame.dispose ();

          }

        });

        break;

...

 

Notice that the method invokeLater is invoked on the AWT EventQueue from the SWT main thread; this is ok because the invokeLater() method is thread-safe.

Thread-Safe Messaging between Swing and SWT

While the SWT_AWT bridge handles disposal, we must explicitly manage how can we send messages between our Swing component and the RCP framework (and vise versa) in a thread-safe way. Seeing how to send events to Swing in a thread-safe way, we now see how we can, in our own code, safely send events between SWT and AWT/Swing. To send an event from SWT to Swing, while on the SWT main thread, we should post a runnable to the Swing Event Dispatch Thread (EDT) using the Swing thread-safe method from the SwingUtilities class, which is SwingUtilities.invokeLater(). Likewise, to send a message from Swing back to SWT (i.e: to the RCP), we should use the SWT thread-safe method from the Display class, which is Display.asyncExec(); This is demonstrated for the Swing-to-SWT case in the example slDemo Rich Client Application. The slDemo places a Swing panel, with a button and a text field, inside an RCP view, and shows how to have the Swing button actionListener post a "status message" to the RCP StatusMessageManager:

사용자 삽입 이미지

To use the slDemo, the user is to enter a message into the text field, and when the button is pressed, a message is sent to the RCP to display the text in the RCP status line (in the lower left hand corner).

From Swing to the RCP

To be thread-safe, we add a listener to the Swing button so that when the button is pressed, the text is retrieved and sent to the RCP using the thread-safe SWT methodDisplay.asyncExec():

...

button.addActionListener(new ActionListener () {

  public void actionPerformed(ActionEvent e) {

    final String message = text.getText();

    Display display = Display.getCurrent();

    if (display == null) display = Display.getDefault();

    if (display != null) {

      display.asyncExec(new Runnable() {

        public void run() {

          setStatusLineMessage(message);

        }

      });

    }

  }

});

...

private void setStatusLineMessage(String message) {

  getViewSite().getActionBars().getStatusLineManager().setMessage(message);

}

The Status Line RCP Demo

The slDemo RCP is a modified version of a sample RCP generated using the Eclipse 3.x RCP wizard (sample code included). We have replaced the auto-generated View with the slView class (enclose code here). Take note of the SlView instance SWT Composite objects parent and swtAwtComponent, as well as the createPartControl(Composite parent) and the setStatusLineMessage(String message) methods. (Also, in order to display the status line message, we modify the default ApplicationWorkbenchWindowAdvisor.preWindowOpen() method by adding the line configurer.setShowStatusLine(true));

The createPartControl() method is called during the initilization cycle of the plugin. Here, the parent object is set, and the swtAwtComponent is created. Notice that that the swtAwtComponent must include the SWT.EMBEDDED . A new awt Frame is then created using the AWT_SWT.newFrame() method discussed above. A JPanel is created that includes a text field and a button with an action listener (as an anonymous class).

Summary

Many Eclipse RCP applications might be built and deployed faster if it is possible to re-use existing Swing components within an RCP View. Doing so, however, may may be non-obvious because neither SWT or Swing is (generally) thread-safe, a naive attempt to integrate a Swing component into an RCP application may cause the platform to deadlock. To solve this, the RCP 3.x platform includes the AWT_SWT bridge class which allows a one to embed a Swing (or AWT) Component into an RCP SWT Composite, and to also dispose of the Composite in a thread-safe way. We review how to use the SWT_AWT bridge and how it achieves thread-safety. We also provide an example RCP (slDemo) that demonstrates how the RCP developer can use send messages in a thread-safe way between an RCP application and a Swing Component embedded in an RCP View.

Message was edited by: Matthew Schmidt
Added his source code as an attachment.

'Eclipse' 카테고리의 다른 글

Eclipse RCP: A Platform for Building Platforms  (0) 2006.08.30
Eclipse - a tale of two VMs (and many classloaders)  (0) 2006.06.18
RCP Tips  (0) 2005.10.20