Java: Howto embed SWT widget into Swing JFrame
Wednesday, 5 January 2011
Today I wanted to embed a SWT component (Browser) into an existing JFrame. This is the way it works:
import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Dimension; import javax.swing.JFrame; import javax.swing.JPanel; import org.eclipse.swt.SWT; import org.eclipse.swt.awt.SWT_AWT; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; /** * A simple canvas that encapsulates a SWT Browser instance. * Add it to a AWT or Swing container and call "connect()" <b>after</b> * the container has been made visible. */ private Browser swtBrowser; /** * Connect this canvas to a SWT shell with a Browser component * and starts a background thread to handle SWT events. This method * waits until the browser component is ready. */ public void connect() { if (this.swtThread == null) { @Override public void run() { try { Display display = new Display(); Shell shell = SWT_AWT.new_Shell(display, canvas); shell.setLayout(new FillLayout()); synchronized (this) { swtBrowser = new Browser(shell, SWT.NONE); this.notifyAll(); } shell.open(); while (!isInterrupted() && !shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } shell.dispose(); display.dispose(); interrupt(); } } }; this.swtThread.start(); } // Wait for the Browser instance to become ready synchronized (this.swtThread) { while (this.swtBrowser == null) { try { this.swtThread.wait(100); this.swtBrowser = null; this.swtThread = null; break; } } } } /** * Returns the Browser instance. Will return "null" * before "connect()" or after "disconnect()" has * been called. */ public Browser getBrowser() { return this.swtBrowser; } /** * Stops the swt background thread. */ public void disconnect() { if (swtThread != null) { swtBrowser = null; swtThread.interrupt(); swtThread = null; } } /** * Ensures that the SWT background thread * is stopped if this canvas is removed from * it's parent component (e.g. because the * frame has been disposed). */ @Override public void removeNotify() { super.removeNotify(); disconnect(); } /** * Opens a new JFrame with BrowserCanvas in it */ <b>// <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=161911">Required for Linux systems</a> // Create container canvas. Note that the browser // widget will not be created, yet. final BrowserCanvas browserCanvas = new BrowserCanvas(); // Add container to Frame frame.setContentPane(panel); frame.pack(); // This is VERY important: Make the frame visible BEFORE // connecting the SWT Shell and starting the event loop! frame.setVisible(true); browserCanvas.connect(); // Now we can open a webpage, but remember that we have // to use the SWT thread for this. @Override public void run() { browserCanvas.getBrowser().setUrl("http://www.google.com"); } }); } }
Comments
François Cassistat (not verified)
28. January 2011 - 17:29
Permalink
Hi Cybso,
On my side, under Mac OS X, I was having a blank canvas with Cocoa warnings in console.
The first warning was about the main thread and manage to prevent by adding -XstartOnFirstThread on my VM parameters.
The next warnings was about NSCondition unlocked when not locked.
Please, let me know if you manage to make this works.
Thank you !
Cybso (not verified)
20. January 2011 - 9:59
Permalink
Good to know. I'll have to implement this into our software the next weeks. So I'll definitly test this under OS X and update this article.
François Cassistat (not verified)
19. January 2011 - 23:35
Permalink
Really nice!
Does not seem to work under Mac OS X though...
Michael Sajuyigbe (not verified)
26. June 2012 - 17:42
Permalink
The browser displays only after the empty window is resized!
Martin Nedbal (not verified)
12. November 2012 - 11:30
Permalink
Hi,
I have similar code and it is working for me - last SWT, last JRE, Windows7. I found your article because I was having problems with it because I was initialising SWT too early - before the Canvas was visible. I'd recommend using addNotify() instead of just putting your connect() call after setVisible() - this would help if you have to hide and re-show it later.
Regards,
Martin
othman (not verified)
29. November 2011 - 21:26
Permalink
doesn't work on Linux. blank(grey) canvas
Tony (not verified)
16. February 2012 - 0:29
Permalink
Hi Cybso,
I've tried the code snippet in a Win7-x64 machine (with swt-3.7RC4-win32-win32-x86_64) and got the same gray canvas as Gourav and othman.
Doing some research I found out that it's needed to refresh the layout cache which is done beneath the covers when resizing the frame.
I found that the refreshing could be achieved by calling the Shell's methods layout(true) and pack(), but for me it didn't work. The pack() call almost got it going, but made the canvas get resized to a little rectangle on the top left.
There was another "workaround" by calling the frame setSize() method like frame.setSize(frame.getWidth() + 1, frame.getHeight() + 1) but it sounded too ugly.
After some testing I finally got a better solution by calling the Shell methods setFullScreen(true) and next pack() just after the setUrl() inside run().
If there is a better solution, please tell us! Thanks for the code snippet.
-Tony
Gaurav (not verified)
9. January 2012 - 7:21
Permalink
Hi Cybso,
I am facing a problem while running this example on 32 bit Windows Vista. When I run this example I get a grey screen and a mouse hour glass icon showing that page is loading, but even after waiting for few minutes grey screen remains as it is and google web page do not appears. If I resize the screen by dragging the corner of the grey screen window of the program, I instantly get to see the web page of google.
Can you suggest what can be reason for this? and what can be work around for this? User running this program will not know that resizing window will make web page appear.
I am running this program unchanged in my Eclipse Java EE IDE for Web Developers(version 3.7.0.v20110530-9gF7UHNFFt4cwE-pkZDJ7oz-mj4OSEIlu9SEv0f) with jdk 1.6 update 27.
looking forward to your reply,
Gaurav
Michael Sajuyigbe (not verified)
26. June 2012 - 18:13
Permalink
Try adding a "frame.setSize(800,600);" as a line
At the last line of d main Method to solve d blank Window problem.
Cybso (not verified)
16. February 2012 - 11:47
Permalink
Hello Tony,
i'm afraid I can't help. The code written above was not longer required in our project so we removed it. I have not done any experiments with SWT and Swing since then.
Cybso (not verified)
19. October 2012 - 9:52
Permalink
Yes, of course. I consider this code as public domain :-)
Koen (not verified)
18. October 2012 - 23:27
Permalink
This is exactly what i needed, i added this file to my project and it worked. (only tested windows so far, XP and W7)
I want to release my project under the Apache License version 2.0. Can i have your permission to include this code?
Nmn (not verified)
17. June 2015 - 11:21
Permalink
Hi,
Hi,
This is a prefect example to use swt shell inside jframe. i want to know why html page rendering is little bit slow have any idea?
Thanks