Tutorial: beautifying the dialogs in Swing applications

Jul 18, 2012 by     34 Comments    Posted under: Tutorials

Today, a tutorial for old-school application designers using the Swing technology. Swing produces UIs that look like windows98 interfaces, but with a bit of tweaking, it’s still a very powerful technology, at least until JavaFX gets bundled in the JRE for all platforms.

Working on a new application, I was getting a bit tired of the dialogs I use everywhere in my apps. They look a bit old-fashioned, and I dislike the modal dialogs in desktop applications as much as the popups in websites. Of course, I though about using layers and glass panels, but I faced one issue: an opengl canvas is a heavy beast, and cannot be masked with any other swing component. Since I nearly always include an opengl canvas (using libGDX LwjglCanvas) in my applications, I’m stuck with dialogs. Fine, so let’s make them more attractive!

Following images show (1) a basic modal dialog, and (2) the same dialog, tweaked.

The method presented here is really simple to implement, and no magic tricks are involved. It can be easily modified to fit any style: just remove what you dislike (shadow, title, etc) and add other elements instead.

1. The method

What I want to do is to avoid having to manually change all my already-made dialogs. Hopefully, this method can take any existing dialog and convert them into the expected result, with only a few (3) lines of code put into the dialog code.

A basic Swing dialog comes as shown in the following illustration. Like every top-level container, it is made of a root panel (JRootPane) which holds a content panel, a layer panel, and a glass panel. A top-level container, like a window or a dialog, is by default opaque and surrounded by a system frame (which holds the title and some buttons to close/minimize/maximize it).

A swing dialog without any changes

To bring the desired effect in place, we need to change that, as shown in next figure. The dialog will be made as large as the underlying window, and placed on top of it. Its content panel will be replaced by a custom panel. This custom panel will hold the original content panel, as well as some labels to display the dialog title for instance. It will also be made transparent, and a shadow image is painted on it, right behind the original content panel.

The same dialog, after applying the method

Therefore, the application frame has not changed at all, everything comes from the dialog itself. This is mandatory to be able to mask every possible widgets, including heavy ones like an opengl canvas. All the code will go in the dialog itself. Of course, we’ll place everything in a utility class, for easy reuse in every dialog.

2. Implementation

When you look at the previous picture, implementation seems trivial. You’re in luck: it is. The following code extract places everything in a utility class with a static method. This single method does all the job: it creates the new dialog transparent back panel, position the components over it, and replaces the original dialog content panel by this new panel. Finally, it sizes and positions the dialog over the underlying window.

public class SwingUtils {
	 * Centers the dialog over the given parent component. Also, creates a
	 * semi-transparent panel behind the dialog to mask the parent content.
	 * The title of the dialog is displayed in a custom fashion over the dialog
	 * panel, and a rectangular shadow is placed behind the dialog.
	public static void createDialogBackPanel(JDialog dialog, Component parent) {
		DialogBackPanel newContentPane = new DialogBackPanel(dialog);
		dialog.setContentPane(newContentPane); // dialog content is replaced by the panel
		dialog.setSize(parent.getSize()); // the dialog is made as wide as the underlying window
		dialog.setLocation(parent.getLocationOnScreen()); // the dialog is placed over this window

	// -------------------------------------------------------------------------

	private static class DialogBackPanel extends JPanel {
		private static final Paint fill = new Color(0xAAFFFFFF, true);
		private static final ImageIcon shadowImage = new ImageIcon(SwingUtils.class.getResource("/res/gfx/dialogShadow.png"));
		private final Component cmp;
		private final JLabel title = new JLabel();
		private final JLabel info = new JLabel("Hit 'ESC' to close the dialog");

		public DialogBackPanel(JDialog dialog) {
			this.cmp = dialog.getContentPane();

			 // Misc
			setOpaque(false); // the panel is transparent

			 // Layout of components
			setLayout(null); // absolute layout

			// Style the components (here I use my Universal CSS Engine,
			// but you can just use common "setForeground()" type methods.
			Style.registerCssClasses(cmp, ".dialogPanel");
			Style.registerCssClasses(title, ".dialogTitleLabel");
			Style.registerCssClasses(info, ".dialogInfoLabel");
			Style.apply(this, new Style(Res.getUrl("css/style.css")));

			// Size the components (required for absolute layouts)

		protected void paintComponent(Graphics g) {

			int w = getWidth();
			int h = getHeight();

			// Location of the components:
			// - the dialog original content panel is centered
			// - the title label is placed over it, aligned left
			// - the info label is placed over it, aligned right
			int shadowX = w/2 - (cmp.getWidth()+100)/2;
			int shadowY = h/2 - (cmp.getHeight()+100)/2;
			cmp.setLocation(w/2-cmp.getWidth()/2, h/2-cmp.getHeight()/2);
			title.setLocation(w/2-cmp.getWidth()/2, h/2-cmp.getHeight()/2-title.getHeight());
			info.setLocation(w/2+cmp.getWidth()/2-info.getWidth(), h/2-cmp.getHeight()/2-info.getHeight());

			// Paint
			Graphics2D gg = (Graphics2D) g.create();
			gg.fillRect(0, 0, w, h);
			gg.drawImage(shadowImage.getImage(), shadowX, shadowY, cmp.getWidth()+100, cmp.getHeight()+100, null);

So how do you use this code? Trivial, you just need to add one line of code at the end of your dialog code. You can even add it outside the dialog code, after you instantiated it with new MyDialog(theParentWindow). Well, actually, I lied a bit: there are 2 other mandatory lines, required to enable the dialog transparency, and to remove the system frame around it. That’s actually 3 lines :)

These first two lines need to be included inside the dialog code, and before anything, else you will get an exception.

public MyDialog(JFrame parent) {
	super(parent, true);

	setUndecorated(true); // remove system frame
	AWTUtilities.setWindowOpaque(this, false); // enable opacity

	... dialog code ...

	SwingUtils.createDialogBackPanel(this, parent.getContentPane());

Et voilà. Your dialogs are up and ready. Well, not totally, we can polish them a bit more, with stuff that cannot be shown in screenshots, but which contribute a lot to the overall user experience.

3. Polishing with fade in/out

For now, when you call setVisible(true) on the dialog, it immediately pops out of nowhere. Indeed, as long as a dialog uses a system frame, the system is able to smoothly fade it in, like for every window of every program. However, as soon as you remove the system frame, dialogs and windows just pop in, without any animation. Cool, that means we can use any animation we want!

The transition I propose is a very basic, linear, opacity fade in/out, so feel free to modify it to be better. Implementation is as follows:

public class SwingUtils {
	 * Creates an animation to fade the dialog opacity from 0 to 1.
	public static void fadeIn(final JDialog dialog) {
		final Timer timer = new Timer(10, null);
		timer.addActionListener(new ActionListener() {
			private float opacity = 0;
			@Override public void actionPerformed(ActionEvent e) {
				opacity += 0.25f;
				dialog.setOpacity(Math.min(opacity, 1));
				if (opacity >= 1) timer.stop();


	 * Creates an animation to fade the dialog opacity from 1 to 0.
	public static void fadeOut(final JDialog dialog) {
		final Timer timer = new Timer(10, null);
		timer.addActionListener(new ActionListener() {
			private float opacity = 1;
			@Override public void actionPerformed(ActionEvent e) {
				opacity -= 0.25f;
				dialog.setOpacity(Math.max(opacity, 0));
				if (opacity 					timer.stop();


To use it, instead of calling dialog.setVisible(true), just call SwingUtils.fadeIn(dialog). And to fade out, do the same at the place you used dialog.dispose() or dialog.setVisible(false).

4. Polishing with “Hit escape to close”

Another feature that is very welcome is to let the users close a dialog by pressing the ESC key, no matter what component has the focus. It is especially important for dialogs without system frame, since buttons are not shown. Moreover, in the method presented in this article, there is no way to move the dialog around, so if the “ok” or “close” button you may have placed in the dialog is placed outside the screen (because the user opened the dialog while the window is not fully visible), there is no way for him to close it.

Thanks to the nice new features of Java7, there is now a JLayer component available, that is meant to let you paint over a component, or intercept some of its events. The last feature is the one we need.

public class SwingUtils {
	 * Adds a glass layer to the dialog to intercept all key events. If the
	 * espace key is pressed, the dialog is disposed (either with a fadeout
	 * animation, or directly).
	public static void addEscapeToCloseSupport(final JDialog dialog, final boolean fadeOnClose) {
		LayerUI layerUI = new LayerUI() {
			private boolean closing = false;

			public void installUI(JComponent c) {
				((JLayer) c).setLayerEventMask(AWTEvent.KEY_EVENT_MASK);

			public void uninstallUI(JComponent c) {
				((JLayer) c).setLayerEventMask(0);

			public void eventDispatched(AWTEvent e, JLayer l) {
				if (e instanceof KeyEvent && ((KeyEvent) e).getKeyCode() == KeyEvent.VK_ESCAPE) {
					if (closing) return;
					closing = true;
					if (fadeOnClose) fadeOut(dialog);
					else dialog.dispose();

		JLayer layer = new JLayer<>(dialog.getContentPane(), layerUI);

So that’s another static method in our utility class. This one replaces the dialog content panel with the JLayer panel, so be sure to call it after createDialogBackPanel. You can also call it directly inside the latter, for more ease.

5. Conclusion

Eventually, we’ve got a nice utility class filled with easy-to-use methods that will bring cool effects instantly in your UIs. I hope that can give you some ideas. The JLayer class seems really powerful, I’m eager to use it a bit more to draw overlays of all sorts.

Demo of the tutorial (with executable jar and sources):

Side note: the Universal CSS Engine has greatly evolved since the 1.0 version. I never made any public release of the new stuff, but I’ll try to do that as soon as I get the time. I think it is now sufficiently mature to be used without fear.

Below are some images showing the steps I went through, from the basic dialog to the target.

34 Comments + Add Comment

  • could you please share your complete project for this example ?

    • Well, the complete project is a whole particle editor, so I think it will be overkill just to learn how dialogs are managed. The editor will be released as open-source in the next days, I still need to implement some stuff.

      However, I’m considering building a small example project to showcase this tutorial. I’ll upload something soon :)

    • And here you are :)

      The demo includes an executable jar, as well as the corresponding sources.

      • Perfect. Thats what i was requesting for. I always had bad experience building Swing apps. It might increase my knowledge.

  • The FX editor looks really nice. Can’t wait to test it. :)

    • Thank, it should be released quite soon, it’s nearly complete now :)

    • You’ve maengad a first class post

    • ds1no / What a whirlwind of a time he had in Hong Kong! Great performances at CASBAA and Fox. David singing ‘Wait’ for the first time live was soooo good!

    • Hmm is anyone else encountering problems with the images on this blog loading? I’m trying to figure out if its a problem on my end or if it’s the blog. Any feed-back would be greatly appreciated.

    • Pour ma part je ne suis pas d’accord avec Simon, les réseaux sociaux c’est l’avenir d’internet. Pour ma part, je dirais qu’il faudrais plus y mettre en avant son coter ludique, du faite qu’on peut obtenir un maximum de traffic en très peu de temps.Cordialement.

    • Is it maybe just that you ‘re suffering a Texan perspective? That is has to be bigger than better?You must know what the Celts believed of immortality. Make your mark so that people remember. Immoertality lies in the collective consciousness…

    • Ake – Great post P. Jason. Thanks for sharing the touching story about Kei and his mom! All the food pictures made me hungry!!Have a safe journey home. Can’t wait to hear all the details from the whole team when you return!!

    • I *SO* could use your help in making a control journal.I am not a SAHM (I wish!) so I’m having trouble trying to figure things out, so I would love any advice you have!It’s been a while since I’ve been at the flylady website… I still do follow some of her advice, but I might need a refresher course! I was never able to get a schedule down or a control journal figured out, I’d write down a few things and then get frustrated and give up.

    • Novi singl Zorana Predina i Matije Dedića premijerno u emisiji Turki Party!…Fresh to SEARCH ENGINE OPTIMISATION? The particular Free Beginner’s Manual on SEO have been review 1 thousand times and supplies the data you should get ranking better…

    • Great Post. Even though I am reading it a year later, the information is still relevant and valuable.Have you made the follow up post on reasons to stay with the company?ThanksClaudia

  • Great news. Will it be compatible to the libGDX particle implementation (i guess… yes ;))?

    • Yes and no :)

      Actually, I built this application in a few hours, just to let me add some simple effects to my libgdx games (hence the name “lil”). I wasn’t able to use the official particle effect class to fit with meter units, so I designed my own effect class in a few minutes.

      The tool will ship with this custom, easy-to-use, particle effect class API, but I want to make it able to export to various implementations, like the official libgdx one (which is by far more powerful than mine).

  • Hi :)

    Thanks for this awesome tutorial. I’m just starting with Swing and I’m trying to make
    my interface as beautiful as possible.
    Could you please answer a few questions?
    What Look and Feel are you using? What did you customize?

    • I’m not using any specific laf, just the system one. However, I play a lot with background and foreground colors for panels and labels. To ease the process, and avoid having to set the properties of every element one by one, I made a CSS engine for Swing [1]. It lets you change the properties of the components with CSS stylesheets. See this [2] for a stylesheet example. It’s the one used to skin my Physics Body Editor tool [3].

      I also made my own components, like the compact sliders visible under the dialog. Nothing heavy, each component is less than 100 lines long. Override paintComponent() to define the visual, add a MouseListener to handle the clicks, and you’re done.

      [1] http://code.google.com/p/java-universal-css-engine/
      [2] http://code.google.com/p/box2d-editor/source/browse/editor/src/res/css/style.css
      [3] http://www.aurelienribon.com/blog/projects/physics-body-editor/

      • Thank you!

      • Lisa, That verse is such a beautiful and comforting promise to us. Your minsitry is so needed in today’s world. I will pray that your daughter and grdundaaghter can come. I want so much for you to have that privilege.

      • Rodrigo11 de maio de 2009Set list bem curto mesmo. Parece até que eles estão só esquentando pra turnê que vão fazer no verão europeu e norte-americano, aí sim com um set list mais elaborado. Mas o que importa? Ainda assim, metade do Black Sabbath original estará lá, sem mencionar a habitual competência de Dio e Appice. E se hoje eu posso dizer que toco guitarra, isso se deve a uma pessoa somente: Tony Iommi. Então, só de vê-lo em ação já vale o ingresso.

      • I tried it at a music store. It’s like a tube screamer. It just makes you a little louder with some hiss and makes you feed back. Good for guitar but useless for harp. It might be good for the PA, but the guitar amp I tried it though already had too much gain for harp.Keith

      • Ahh the Republicans, you can always count on them to exploit religion. Here we have yet another shyster that worships the perverted messiah known as Supply-Side Jesus. Fortunately, only the very dumbest of Ozark rubes are still willing to fall for such faux populist bullshit.

      • Sacrificiu Final:Spin-offul se numeste Bloodlines.Orasul de Cenusa:Volumele se numesc Clockwork Angel;Clockwork Prince si Clockwork Princess.Am dat friend request editurii pe fb sub numele de Theo Roman.

  • Any news about particle editor? :)

    Thank you for all these great tools.

    • I first want to complete the next major update of gdx-setup, and then I’ll release the particle editor :)

      • really looking forward to particle editor :)

  • [...] would have been modal dialogs, like what I do in nearly every other tool I made. I even wrote a tutorial about how to create pretty dialogs. However, this requires Java7, and I’m quite bored of dialogs. I could also use a tabbed [...]

  • thank you for this tutorial.. ^_^

  • sir…
    plz give some easy and understandable simple code to make project attractive……

  • Aw, this was a very nice post. Finding the time and actual effort to
    produce a good article… but what can I say… I put things off a whole lot and don’t seem to get
    anything done.

  • Well done Auralien. well written and good tutorial

  • Gamer Testing Floor is a one in every of a form web site that gives those involved in gamer testing jobs the data and support they should
    get into the intense and profitable world of video game testing.

Got anything to say? Go ahead and leave a comment!

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>