Messing around with the title bar of a JFrame

I’v been surfing about, and it seems like most places agree: You can’t change the title bar of a JFrame.

Some people suggest stuff like hiding the title bar and building your own (faking it with a JPanel). But it’s messy and probably won’t be perfect (especially if you are using a special look and feel). I thought I would ask you guys if you have any good ideas of how the content of the title bar can be changed.

I’m thinking of stuff like adding additional buttons next to the minimize/maximize/close buttons, removing the close button, making the maximize button react to right mouse-click and so forth. This can be done in other languages so it of course should be possible in Java. It may not be easy but it should be possible. And if it truly is so, it is too bad that you have to “fake it”.

I’m posting this because I wanted to make it possible to minimize my JFrame to the system tray (that’s “next to the clock”) when you right-click the close “X” instead of left-clicking it (left-clicking it should still close the window as usual/pass a event to WindowListener). When that wasn’t easy to do I instead wanted to add a extra button to the left of the minimize button (the icon would have been a dot) that would do the same thing. As you understand that wasn’t an easy task either.

So, anyone got a good method of changing how the title bar works?

Oh and before anyone suggests it, no you can’t just catch mouseClicked events of the window’s title bar and then figure out if you clicked the “X” from the event’s X/Y location. Two reasons: First of all the close button’s location is not guaranteed to be the same on all systems so it wouldn’t have been that good of a solution in the first place, second (and primarily) the close button cunsumes the event so it can’t be catched. :frowning:

As I have it now I just catch a right-click on the entire title bar and then minimize the window. It works but it wasn’t what I really wanted. Here’s the code that allows me to get the title bar (there’s not that much that can be done with it, but it has “addMouseListener()”).

theJFrameInstance.getLayeredPane().getComponent(1);

This appears to only work if “JFrame.setDefaultLookAndFeelDecorated(true);” has been called, and if “UIManager.setLookAndFeel(~)” is not called the window may not be draggable and the title won’t react to double-click.

Any way, that was a bit off topic, do go on. :slight_smile:

This simply isn’t possible in Swing. The behavior you want is very platform-specific, you’d definitely have to write some JNI to accomplish this.

Also, I don’t think the “frame.getLayeredPane().getComponent(1)” will work on all platforms. At least, it isn’t guaranteed to work everywhere. :wink:

The whole “right-click on the window close button” thing is not intuitive to me though. Are there other, “real-world” applications that do this? On Windows at least, some apps minimize to the system tray when the ‘_’ icon is clicked. You could certainly do that in Java easily enough - use the SystemTray class for the actual tray icon, and listen for WINDOW_ICONIFIED WindowEvents to toggle the visibility of your window.

why not just hide it, and up top draw a “fake” title bar that looks like the real one but with what you want. Could be cool.

I never tried to do any of this until I saw your post so it’s probably the wrong way to do it but still it shows it’s possible. I use the minimize button to place it in the system tray and most of the code is from the SystemTray javadoc, the rest is hastily thrown together. I believe you could add/change the title bar buttons through a custom laf but I haven’t actually checked and a fake title bar would probably be an easier solution.

import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;




public class SystemTrayTest extends JFrame {
	TrayIcon trayIcon = null;

	public SystemTrayTest() {
		super("System Tray Test");
		JPanel panel = new JPanel();
		panel.setPreferredSize(new Dimension(200,200));
		add(panel);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		pack();
		setVisible(true);

		// load an image
		Image trayImage = Toolkit.getDefaultToolkit().getImage("icon.png");
		// create a action listener to listen for default action executed on the tray icon
		ActionListener listener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String cmd = e.getActionCommand();
				if("Exit".equals(cmd))
					System.exit(0);
				if("Restore".equals(cmd))
					restore();
			}
		};
		// create a popup menu
		PopupMenu popup = new PopupMenu();
		// create menu item for the default action
		MenuItem exitItem = new MenuItem("Exit");
		exitItem.addActionListener(listener);
		popup.add(exitItem);
		MenuItem defaultItem = new MenuItem("Restore");
		defaultItem.addActionListener(listener);
		popup.add(defaultItem);
		/// ... add other items
		// construct a TrayIcon
		trayIcon = new TrayIcon(trayImage, "Tray Demo", popup);
		// set the TrayIcon properties
		trayIcon.addActionListener(listener);
		// ...
		// add the tray image
	}

	@Override
	protected void processWindowEvent(WindowEvent e) {
		super.processWindowEvent(e);
		if(e.getID() == WindowEvent.WINDOW_ICONIFIED)
			minimize();
	}

	public void restore(){
		if (SystemTray.isSupported()) {
			setVisible(true);
			setState(NORMAL);
			SystemTray.getSystemTray().remove(trayIcon);
		} else {
			// disable tray option in your application or
			// perform other actions
		}
	}

	public void minimize(){
		if (SystemTray.isSupported()) {
			setVisible(false);
			// get the SystemTray instance
			SystemTray tray = SystemTray.getSystemTray();
			try {
				tray.add(trayIcon);
			} catch (AWTException e) {
				System.err.println(e);
			}
			// ...
		} else {
			// disable tray option in your application or
			// perform other actions
		}

	}


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new SystemTrayTest();
	}

}

[quote=“BoBear2681,post:3,topic:33723”]
I’m using a small ~150 KiB application called “TrayIt!” that I downloaded years ago from some place that makes it possible to right-click on all window’s “X” button and then minimize it to the system tray. I use this feature all the time, it allows you to hide away stuff that you aren’t working with right now and then bring it back later. I wish it was like that by default in Windows (that if you right-click any of the minimize/maximize/close buttons it will minimize to system tray).

Your post made me think a bit and you’re right, it’s not guaranteed to work on all platforms. I’m going to have to find another way of doing it… painting a small icon just below the title bar maybe? Too bad because I really wanted it to be in the title bar.

[quote=“SunshineKiller,post:4,topic:33723”]
Yeah, but I mentioned in my original post that that is a bit messy, especially if you want it to look good and be draggable etc. But it’s probably the only way to make your own title bar in a JFrame.

[quote=“zoto,post:5,topic:33723”]
I already knew how to minimize the JFrame to the system tray, but thanks for the code nontheless. It may certainly be of use for others reading the thread. :slight_smile: I never thought of using the processWindowEvent() method though, interesting.

Hm, here’s something interesting, if I call “setUndecorated(false);” in the JFrame’s constructor I get two title bars. Apparently the title bar I attach the MouseListener to is a fake one created by the look and feel I’m loading… Interesting, it should be possible to change it somehow…

Edit: Cool, I can disable the “X”. I’m using a Substance look and feel, and by using a SubstanceLookAndFeel method in the JFrame’s constructor I can get the JComponent of the title bar. Then I can disable the “X”, like so:

JComponent titleBar = SubstanceLookAndFeel.getTitlePaneComponent(this);
titleBar.getComponent(3).setEnabled(false);

I bet I can add a mouseListener to the “X” button now if I want to. :slight_smile: But I’ll try to see if it’s possible to insert new buttons first.

If you haven’t heard of Substance yet, check it out: https://substance.dev.java.net/
With it Java applications can look really nice.

Edit: Well, it didn’t go so well. I thought I could just add another component to the titleBar, that would have been logical since the titleBar is a JComponent. But no go. It’s weird because I also can’t disable the maximize button for some reason, maybe its nestled in some way. But even weirder is that doing “removeAll()” on the titleBar does nothing. Also can’t change stuff like the background color. I’m bewildered. At least I got my “minimize to tray on right-click” behaviour on the close button, and since I’m now using the “getTitlePaneComponent(~)” method I’m pretty sure that it will work on all systems.