Skip to content

Instantly share code, notes, and snippets.

@r10r
Created April 4, 2012 19:49
Show Gist options
  • Save r10r/2305091 to your computer and use it in GitHub Desktop.
Save r10r/2305091 to your computer and use it in GitHub Desktop.
embed SWT widget into Swing JFrame
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()" after
* the container has been made visible.
*/
public class BrowserCanvas extends Canvas {
private Thread swtThread;
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) {
final Canvas canvas = this;
this.swtThread = new Thread() {
@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();
} catch (Exception e) {
interrupt();
}
}
};
this.swtThread.start();
}
// Wait for the Browser instance to become ready
synchronized (this.swtThread) {
while (this.swtBrowser == null) {
try {
this.swtThread.wait(100);
} catch (InterruptedException e) {
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
*/
public static void main(String[] args) {
// Required for Linux systems
System.setProperty("sun.awt.xembedserver", "true");
// Create container canvas. Note that the browser
// widget will not be created, yet.
final BrowserCanvas browserCanvas = new BrowserCanvas();
browserCanvas.setPreferredSize(new Dimension(800, 600));
JPanel panel = new JPanel(new BorderLayout());
panel.add(browserCanvas, BorderLayout.CENTER);
// Add container to Frame
JFrame frame = new JFrame("My SWT Browser");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
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.
browserCanvas.getBrowser().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
browserCanvas.getBrowser().setUrl("http://www.google.com");
}
});
}
}
@coldcodecold
Copy link

It seems that panel can't display the browser on canvas

Only by this way can I see browser
Container cp = frame.getContentPane();
Canvas canvas = new Canvas();
cp.add(canvas,BorderLayout.CENTER);
frame.setVisible(true);

I want to know why.......

@caprica
Copy link

caprica commented Oct 8, 2013

This is a very useful gist, but I always see native errors (at least on Linux64) when I dispose the JFrame, either X-Window errors, or warnings about plugin failures (where the URL is www.google.com).

What I had to do was get rid of the removeNotify() override (seems it is too late to disconnect() here), and instead add a WindowListener to the frame and invoke disconnect() inside the WindowClosing event. It seems to be OK, but I'm not 100% convinced.

@caprica
Copy link

caprica commented Oct 8, 2013

FWIW, I wrote an alternative implementation here: https://gist.github.com/caprica/6890618

The significant differences are that my implementation uses java.util.concurrent objects for the synchronisation, and it shuts down cleanly (no fatal crashes) when the frame is disposed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment