Wednesday, December 20, 2006

Closing Tabs with Swing

So I've been trying to find an elegant way to close tabs in Swing and it turns out to be pretty tough. Not tough to implement, but tough to do it elegantly.

It's very common these days to have an X on the tab or on the tab bar like the following screenshots from your favorite web browsers:

Firefox 1.X


Firefox 2.X


Internet Explorer 7.X


But this isn't supported in Swing because you can currently only have text, an icon, or both. You can't put arbitrary Component's into a tab. There are some workarounds (hacks?) out there, but they are not pretty.

This isn't really the end of the world because many applications make do without it and you barely even notice that they don't have the X. Possibly because they limit the number of tabs that will be visible at a time. Intellij Idea is a good example of this. You can only close tabs by right clicking on the tab or using a keyboard shortcut. But since it's limited to something like 10 tabs by default (configurable in your settings), the tabs never get out of hand you don't really need to close them.

Intellij Idea


How to Close Tabs with a Right Click Context Menu


So here's a quick tip on how to do it with a right click context menu.

Make a class that implements MouseListener and ActionListener

public class CloseTabListener implements MouseListener, ActionListener {

Make a JPopupMenu:

popup = new JPopupMenu();
JMenuItem menuItem = new JMenuItem("Close Tab");
menuItem.addActionListener(this);
popup.add(menuItem);

Implement mousePressed and mouseReleased like so:

public void mousePressed(MouseEvent e) {
showPopup(e);
}
private void showPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
source = e.getSource();
clickPoint = e.getPoint();
popup.show(e.getComponent(),
e.getX(), e.getY());
}
}
public void mouseReleased(MouseEvent e) {
showPopup(e); // here because different platforms handle popups differently
}
In the actionPerformed method:

public void actionPerformed(ActionEvent e) {
for(int i = 1; i < rect =" tabbedPane.getUI().getTabBounds(tabbedPane,">


Then finally you have to register this listener on your JTabbedPane:

tabbedPane.addMouseListener(new CloseTabListener(tabbedPane));


And that should do it. It's a good solution until Java 6 Mustang comes out with better tabs.

How to Close Tabs with a Keyboard Shortcut


And while you're at it, you might as well add the ctrl-w keyboard shortcut too, by creating a KeyListener that implements keyTyped() like this:

public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == '') { // ctrl-w - close tab
tabbedPane.remove(tabbedPane.getSelectedIndex());
}
}


2 comments:

Piotr ZieliƄski said...

You've left unfinished code in this article. Can You fix it? Thanks in advance. Despite this, great article. Short and concrete. Best regards!

Mr Ramon said...

you can add components to the tab "tab" itself
http://docs.oracle.com/javase/tutorial/uiswing/components/tabbedpane.html#tabscomponents