In previous article, I introduced basic about JTabbedPane. Today, we will learn more to custom JTabbedPaen better than, like the image below, it have button close the tab, add new tab,…

tùy biến JTabbedPane

The most important is how to get button to add new tab, how to add button close tab in each tab. We will create two file, one file to custom tab (it contain a JLabel displaying tab title and close button tab), one file create JTabbedPane use customzied tab.

Action add new tab for JTabbedPane

To creating a button to add new tab, we create a tab has title is plus (“+”) and set change event to JTabbedPane. Each switch tab, it will check and if you click on this tab, one new tab will created. Here is code to create customized JTabbedPane.

package nguyenvanquan7826.JTabbedPane;

import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * --------------------- @author nguyenvanquan7826 ---------------------
 * ------------------ website: nguyenvanquan7826.com -------------------
 * ---------- date: Jul 24, 2014 - filename: DemoCustomJTabPane.java ----------
 */
public class DemoCustomJTabbedPane extends JFrame {
	JTabbedPane tabbedPane;
	int numTabs;

	public DemoCustomJTabbedPane() {
		createGUI();
		setDisplay();
	}

	/** set diplay for JFrame */
	private void setDisplay() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(450, 300);
		setLocationRelativeTo(null);
		setVisible(true);
	}

	/** set title and add JTabbedPane into JFrame */
	private void createGUI() {
		setTitle("Demo custum JTabbedPane");
		createJTabbedPane();
		add(tabbedPane);
	}

	/** create JTabbedPane contain 2 tab */
	private void createJTabbedPane() {
		/* create JTabbedPane */
		tabbedPane = new JTabbedPane(JTabbedPane.TOP,
				JTabbedPane.SCROLL_TAB_LAYOUT);

		/* add first tab */
		tabbedPane.add(createJPanel(), "Tab " + String.valueOf(numTabs),
				numTabs++);
		tabbedPane.setTabComponentAt(0, new DemoCustomTab(this));

		/* add tab to add new tab when click */
		tabbedPane.add(new JPanel(), "+", numTabs++);

		tabbedPane.addChangeListener(changeListener);
	}

	/** create JPanel contain a JLabel */
	private JPanel createJPanel() {
		JPanel panel = new JPanel(new GridLayout(1, 1));
		panel.add(new JScrollPane(createTextArea(10, 40)));
		return panel;
	}

	private JTextArea createTextArea(int row, int col) {
		JTextArea ta = new JTextArea(row, col);
		ta.setWrapStyleWord(true);
		ta.setLineWrap(true);
		ta.setForeground(Color.BLUE);
		return ta;
	}

	ChangeListener changeListener = new ChangeListener() {
		@Override
		public void stateChanged(ChangeEvent e) {
			addNewTab();
		}
	};

	private void addNewTab() {
		int index = numTabs - 1;
		if (tabbedPane.getSelectedIndex() == index) { /* if click new tab */
			/* add new tab */
			tabbedPane.add(createJPanel(), "Tab " + String.valueOf(index),
					index);
			/* set tab is custom tab */
			tabbedPane.setTabComponentAt(index, new DemoCustomTab(this));
			tabbedPane.removeChangeListener(changeListener);
			tabbedPane.setSelectedIndex(index);
			tabbedPane.addChangeListener(changeListener);
			numTabs++;
		}
	}

	public void removeTab(int index) {
		tabbedPane.remove(index);
		numTabs--;

		if (index == numTabs - 1 && index > 0) {
			tabbedPane.setSelectedIndex(numTabs - 2);
		} else {
			tabbedPane.setSelectedIndex(index);
		}

		if (numTabs == 1) {
			addNewTab();
		}
	}

	public static void main(String[] args) {
		new DemoCustomJTabbedPane();
	}
}

You pay attention in line 51, we add first tab as usual, then in line 53 we set Component to replace the default tab by tab we customize has close tab button.

Line 58 set event listener transfer tab of JTabbedPane.

addNewTab method to add new tab. In line 91, after adding a new tab, we need remove listener of JTabbedPane because otherwise the condition tabbedPane.getSelectedIndex() == index is always true and it will create a lot more tabs. After remove listener, we set tab selected is the newly created tab and then reset listener.

removeTab will close the tab in position index. The frist if-else statement to check if last tab is closed, it will focus on previous tab, if not it focus on next tab. The second if statement check if all tab is closed (only one button to add new tab) then it will auto create new tab.

Additon close tab button

To create close tab button, we need custom components of tab is a JPanel, this contain JLabel to display tab title and a JButton to close tab as:

thêm nút đóng tab vào JTabbedPane

Code custom component tab.

package nguyenvanquan7826.JTabbedPane;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;

/**
 * --------------------- @author nguyenvanquan7826 ---------------------
 * ------------------ website: nguyenvanquan7826.com -------------------
 * ---------- date: Jul 24, 2014 - filename: DemoButtonTab.java ----------
 */
public class DemoCustomTab extends JPanel {

	DemoCustomJTabbedPane customJTabbedPane;

	/** JPanel contain a JLabel and a JButton to close */
	public DemoCustomTab(DemoCustomJTabbedPane customJTabbedPane) {
		this.customJTabbedPane = customJTabbedPane;
		setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
		setBorder(new EmptyBorder(5, 2, 2, 2));
		setOpaque(false);
		addLabel();
		add(new CustomButton("x"));
	}

	private void addLabel() {
		JLabel label = new JLabel() {
			/** set text for JLabel, it will title of tab */
			public String getText() {
				int index = customJTabbedPane.tabbedPane
						.indexOfTabComponent(DemoCustomTab.this);
				if (index != -1) {
					return customJTabbedPane.tabbedPane.getTitleAt(index);
				}
				return null;
			}
		};
		/** add more space between the label and the button */
		label.setBorder(new EmptyBorder(0, 0, 0, 10));
		add(label);
	}

	class CustomButton extends JButton implements MouseListener {
		public CustomButton(String text) {
			int size = 15;
			setText(text);
			/** set size for button close */
			setPreferredSize(new Dimension(size, size));

			setToolTipText("close the Tab");

			/** set transparent */
			setContentAreaFilled(false);

			/** set border for button */
			setBorder(new EtchedBorder());
			/** don't show border */
			setBorderPainted(false);

			setFocusable(false);

			/** add event with mouse */
			addMouseListener(this);

		}

		/** when click button, tab will close */
		@Override
		public void mouseClicked(MouseEvent e) {
			int index = customJTabbedPane.tabbedPane
					.indexOfTabComponent(DemoCustomTab.this);
			if (index != -1) {
				customJTabbedPane.removeTab(index);
			}
		}

		@Override
		public void mousePressed(MouseEvent e) {
		}

		@Override
		public void mouseReleased(MouseEvent e) {
		}

		/** show border button when mouse hover */
		@Override
		public void mouseEntered(MouseEvent e) {
			setBorderPainted(true);
			setForeground(Color.RED);
		}

		/** hide border when mouse not hover */
		@Override
		public void mouseExited(MouseEvent e) {
			setBorderPainted(false);
			setForeground(Color.BLACK);
		}
	}
}

In this class we have DemoCustomJTabbedPane object, which is allows us to get JTabbedPane is doing.

This class extends JPanel so that it is a JPanel as we want. We will add JLabel and JButton in the 30 and 31 lines.

addLabel method toadd JLabel into JPanel. But we need to get title of tab to display on JLabel by override the getText method.

Addition JButton into JPanel very easy, you just create JButton with text as “x”. But if you do so then it very loud and bad, so I also custom this via CustomButtom class.
This class implements MouseListener to get mouse events. When you hover the close button, mouseEntered will execute and color of character “x” will change to red, show border and tool tip text show up. When taken out, it is returned to normal by mouseExited method.

To get the things this, we need to set some value to it as:
– Set the appropriate size: setPreferredSize (new Dimension (size, size));
– Make transparent button: setContentAreaFilled (false);
– Set Border setBorder (new EtchedBorder ()); setBorderPainted (false);
When you click on the tab close button, mouseClicked method is called and removeTab method of DemoCustomJTabbedPane execute.

Read vietnamese version here