Embed WPF and WinForms components in Swing applications

Previously, we showed how JNBridgePro can be used to embed Swing components in Windows Presentation Foundation (WPF) and Windows Forms applications. In this post, we’ll show how the opposite direction also works: WPF and WinForms components can be embedded in Swing applications. The demos included in the JNBridgePro installation focus on embedding involving Java Abstract Windowing Toolkit (AWT) technology. What those demos leave unsaid is that Swing can be embedded just as easily as AWT can be.

We’ll start with our existing example showing how a WPF component can be embedded inside an AWT application, then show how easy it is to convert the example to use Swing.

First, download the example code and document, and work through the example. Once you’ve done that, come back here and follow the instructions to change an AWT example into a Swing example.

Now that you’ve set up the example using AWT, open the Java class MainClass and change it so that it looks like the code below. Note that the paths in your code may be different from the paths on our machine, and you should adjust accordingly.

package javaTest;

import com.jnbridge.jnbcore.*;

import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import com.jnbridge.embedding.DotNetControl;

import System.Windows.Forms.Application;

import java.util.Properties;

import javax.swing.JFrame;		// added to Swing example
import javax.swing.JLabel;		// added to Swing example
import javax.swing.JTextField;	// added to Swing example

import WPFControlDemo.UserControl1;
import WPFControlDemo.clickDelegate;



public class MainClass {
	
	static JTextField echo;		// Swing example: changed from TextField
	
	public static class ClickEventHandler implements clickDelegate
	{
		public void Invoke(String message)
		{
			echo.setText(message);
		}
	}
	
	static boolean mustStop = false;

	public static void main(String[] args) {
		// configure JNBridgePro
		Properties props = new Properties();
		props.put("dotNetSide.serverType", "sharedmem");
		props.put("dotNetSide.assemblyList.1", "../DotNet/bin/Debug/WPFControlDemo.dll");
		// if using .NET 4.0, change paths below to point to 4.0-targeted components
		props.put("dotNetSide.javaEntry", "C:/Program Files (x86)/JNBridge/JNBridgePro v7.2/2.0-targeted");
		props.put("dotNetSide.appBase", "C:/Program Files (x86)/JNBridge/JNBridgePro v7.2/2.0-targeted");
		props.put("dotNetSide.apartmentThreadingModel", "STA");
		
		DotNetSide.init(props);
		
		JFrame f = new JFrame();		// Swing example: changed from Frame
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	// added to Swing example
		f.setLayout(new GridBagLayout());
		f.setTitle("Embedded WPF Control -- JFrame");
		f.setBackground(Color.LIGHT_GRAY);
		f.setSize(500, 500);

		Font font = new Font("Sans Serif", Font.BOLD, 14);

		JLabel lLeft = new JLabel("WPF UserControl");	// Swing example: changed from Label
		lLeft.setFont(font);

		GridBagConstraints lLeftConstraints = new GridBagConstraints();
		lLeftConstraints.gridx = 0;
		lLeftConstraints.gridy = 0;
		lLeftConstraints.gridwidth = 1;
		lLeftConstraints.gridheight = 1;
		lLeftConstraints.fill = GridBagConstraints.HORIZONTAL;
		lLeftConstraints.anchor = GridBagConstraints.NORTHWEST;
		lLeftConstraints.insets = new Insets(3, 3, 1, 5);
		f.getContentPane().add(lLeft, lLeftConstraints);	// Swing example: added getContentPane()

		echo = new JTextField("", 15);	// Swing example: changed from TextField

		GridBagConstraints dncConstraints = new GridBagConstraints();
		dncConstraints.gridx = 0;
		dncConstraints.gridy = 1;
		dncConstraints.gridwidth = 1;
		dncConstraints.gridheight = 1;
		dncConstraints.fill = GridBagConstraints.NONE;
		dncConstraints.anchor = GridBagConstraints.NORTHWEST;
		dncConstraints.insets = new Insets(0, 3, 3, 5);

		//
		// this is the part where we create and embed the .NET control
		//
		
		// create the WPF control
		UserControl1 c = new UserControl1();
		// register any callbacks
		ClickEventHandler ceh = new ClickEventHandler();
		c.registerClickDelegate(ceh);
		// wrap it so it can be embedded
		DotNetControl dnc = new DotNetControl(c);
		// size it
		dnc.setSize(300, 390);
		// embed it
		f.getContentPane().add(dnc, dncConstraints);	// Swing example: added getContentPane

		JLabel lRight = new JLabel("Text from WPF");	// Swing example: changed from Label
		lRight.setFont(font);

		GridBagConstraints lRightConstraints = new GridBagConstraints();
		lRightConstraints.gridx = 1;
		lRightConstraints.gridy = 0;
		lRightConstraints.gridwidth = 1;
		lRightConstraints.gridheight = 1;
		lRightConstraints.fill = GridBagConstraints.HORIZONTAL;
		lRightConstraints.anchor = GridBagConstraints.NORTHWEST;
		lRightConstraints.insets = new Insets(3, 5, 1, 3);
		f.getContentPane().add(lRight, lRightConstraints);	// Swing example: added getContentPane()

		GridBagConstraints echoConstraints = new GridBagConstraints();
		echoConstraints.gridx = 1;
		echoConstraints.gridy = 1;
		echoConstraints.gridwidth = 1;
		echoConstraints.gridheight = 1;
		echoConstraints.fill = GridBagConstraints.HORIZONTAL;
		echoConstraints.anchor = GridBagConstraints.NORTHWEST;
		echoConstraints.insets = new Insets(35, 5, 3, 3);
		f.getContentPane().add(echo, echoConstraints);	// Swing example: added getContentPane()

		f.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent evt) {
				Window w = evt.getWindow();
				w.setVisible(false);
				w.dispose();
				mustStop = true;
			}
		});

		f.setVisible(true);
		
		while(!mustStop)
		{
			Application.DoEvents();
		}
	}

}

In the code above, we’ve marked the places where you need to change your code to use Swing. This mainly involves changing references to classes Frame, Label, and TextField to JFrame, JLabel, and JTextField, and also adding calls to getContentPane() before adding child components to the JFrame. We’ve also specified that the default close operation on the JFrame is to exit the application.

Once you’ve made those changes and compiled the code, run the application. You should see this:

wpf_in_swing

It looks just like the AWT version from the original example, doesn’t it?

Embedding WPF or WinForms inside Swing is simple. Just write and build your WPF or WinForms component, then proxy it to the Java side and wrap the Java-side proxy inside a com.jnbridge.embedding.DotNetControl, which is supplied by us as part of the JNBridgePro API. Use the wrapped proxy wherever you’d use a java.awt.Component, which includes any Swing element.

Are you creating Swing applications containing .NET components? Any other Java/.NET UI embedding scenarios you’d like to see us support? Contact us and let us know.