The JTabbedPane in Java Swing has no close button, but in modern software, which has a closeable TabbedPane is very useful and common. In this tutorial, we'll teach you to create a closeable JTabbedPane using the popup menu in JSwing applications.
You will learn how to:
- Add a ListSelectionListener to verify if the selected item has changed.
- Set up a popup menu to close JTabbedPane tabs
- Add a hyperlinkUpdate event handler to open the URL when a hypertext link of the JTextPane is clicked.
Prerequisites
Before you begin to read this tutorial, you must:
- Familiar with Java swing development. Go to Oracle Java Swing to get the tutorial.
- Familiar with the first three tutorials on JSwing.
- Familiar with the Operation of Apache NetBeans.
- Familiar with the timing and object of ListSelectionListener and hyperlinkUpdate get called.
Create a Form
- Create a JFrame named CloseableJTabbedPane on the form of the packages, and then drag the necessary components onto the form, the tree diagram as shown in the following figure.
- Change the properties of the components as shown in the table below.
Components text actionCommand name jButton1 Cancel Cancel Cancel jButton2 Help Help Help jButton3 Check for Newest Check for Newest Check for Newest jButton4 Install Install Install jButton5 Select All Select All Select All jButton6 Deselect All Deselect All Deselect All jTabbedPane1 tabbedPane jTable1 plugin_tb jEditorPane1 Install_desc - After the successful step above, Press Ctrl-S to save it, and then press F9 to Compile the Form, and the preview is as below.
Create an App
Create a Java class named CloseableJTabbedPane on the app, and then add code to the Class.
package app;
import javax.swing.JMenuItem;
import javax.swing.event.ListSelectionEvent;
import jswing.application.*;
public class CloseableJTabbedPane extends App {
static {
try {
javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Form.open("form.CloseableJTabbedPane","CloseableJTabbedPane");
UserInterface.initialize("app.CloseableJTabbedPane",Form.getCurrentForm());
}
});
}
private static void tableInit(){
final Object dataVector[][] = {
{false,"Backlog Support","Base IDE"},
{false,"GitHub Issues Support","Base IDE"},
{false,"jVi Update Center JDK-11","com.raelity.jvi"},
{false,"PHP Version Switcher","com.vetaxsoftware.netbeans.module.php"},
{false,"Netbeans Case Convert","Editing"},
{false,"Color Code Preview","Editing"},
{false,"nb-noext-mime-resolver","Editing"},
{false,"Change Line Endings on Save","Editing"}
};
final String columnName[] = {"Install","Name","Category"};
//Description
final String descr[] = {
"<html>\n" +
" <p style=\"margin-top: 0;\">Community Contributed Plugin<br>" +
"Version: 0.9.0<br>" +
"Author: Junichi Yamamoto<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-backlog-plugin\" target=_blank>Plugin Description</a><br>" +
"This plugin provides support for backlog.<br>" +
"Features<br>" +
"<ul>" +
"<li>Add an issue</li>" +
"<li>Update an issue</li>" +
"<li>Create queries</li>" +
"<li>Find issues</li>" +
"<li>Schedules</li>" +
"<li>Resources</li>" +
"</ul>" +
"<a href=\"https://github.com/junichi11/Backlog4j\" target=_blank alt=\"go\">Backlog4j</a><br>" +
" </p>\n" +
"</html>\n",
"<html> \n" +
"Community Contributed Plugin<br>" +
" Version: 0.6.0<br>" +
"Author: junichi11(Junichi Yamamoto)<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-github-issues-plugin\">Plugin Description</a><br>" +
"This plugin provides support for GitHub Issue Tracker.<br>" +
"Features<br>" +
"<ul>" +
"<li>Create a new issue</li>" +
"<li>Edit an issue</li>" +
"<li>Create queries</li>" +
"<li>Edit an issue comment</li>" +
"<li>Delete an issue comment</li>" +
"<li>Create a new pull request</li>" +
"</ul>" +
"Change an existing issue to a pull request<br>" +
"Search issues with issue number or keywords<br>" +
"Create a new label<br>" +
"Create a new milestone<br>" +
"Set a schedule for an issue</html>\n",
"<html>\n" +
" <p style=\"margin-top: 0;\">Community Contributed Plugin<br>" +
"Version: 0.9.0<br>" +
"Author: Junichi Yamamoto<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-backlog-plugin\" target=_blank>Plugin Description</a><br>" +
"This plugin provides support for backlog.<br>" +
"Features<br>" +
"<ul>" +
"<li>Add an issue</li>" +
"<li>Update an issue</li>" +
"<li>Create queries</li>" +
"<li>Find issues</li>" +
"<li>Schedules</li>" +
"<li>Resources</li>" +
"</ul>" +
"<a href=\"https://github.com/junichi11/Backlog4j\" target=_blank alt=\"go\">Backlog4j</a><br>" +
" </p>\n" +
"</html>\n",
"<html> \n" +
"Community Contributed Plugin<br>" +
" Version: 0.6.0<br>" +
"Author: junichi11(Junichi Yamamoto)<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-github-issues-plugin\">Plugin Description</a><br>" +
"This plugin provides support for GitHub Issue Tracker.<br>" +
"Features<br>" +
"<ul>" +
"<li>Create a new issue</li>" +
"<li>Edit an issue</li>" +
"<li>Create queries</li>" +
"<li>Edit an issue comment</li>" +
"<li>Delete an issue comment</li>" +
"<li>Create a new pull request</li>" +
"</ul>" +
"Change an existing issue to a pull request<br>" +
"Search issues with issue number or keywords<br>" +
"Create a new label<br>" +
"Create a new milestone<br>" +
"Set a schedule for an issue</html>\n",
"<html>\n" +
" <p style=\"margin-top: 0;\">Community Contributed Plugin<br>" +
"Version: 0.9.0<br>" +
"Author: Junichi Yamamoto<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-backlog-plugin\" target=_blank>Plugin Description</a><br>" +
"This plugin provides support for backlog.<br>" +
"Features<br>" +
"<ul>" +
"<li>Add an issue</li>" +
"<li>Update an issue</li>" +
"<li>Create queries</li>" +
"<li>Find issues</li>" +
"<li>Schedules</li>" +
"<li>Resources</li>" +
"</ul>" +
"<a href=\"https://github.com/junichi11/Backlog4j\" target=_blank alt=\"go\">Backlog4j</a><br>" +
" </p>\n" +
"</html>\n",
"<html> \n" +
"Community Contributed Plugin<br>" +
" Version: 0.6.0<br>" +
"Author: junichi11(Junichi Yamamoto)<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-github-issues-plugin\">Plugin Description</a><br>" +
"This plugin provides support for GitHub Issue Tracker.<br>" +
"Features<br>" +
"<ul>" +
"<li>Create a new issue</li>" +
"<li>Edit an issue</li>" +
"<li>Create queries</li>" +
"<li>Edit an issue comment</li>" +
"<li>Delete an issue comment</li>" +
"<li>Create a new pull request</li>" +
"</ul>" +
"Change an existing issue to a pull request<br>" +
"Search issues with issue number or keywords<br>" +
"Create a new label<br>" +
"Create a new milestone<br>" +
"Set a schedule for an issue</html>\n",
"<html>\n" +
" <p style=\"margin-top: 0;\">Community Contributed Plugin<br>" +
"Version: 0.9.0<br>" +
"Author: Junichi Yamamoto<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-backlog-plugin\" target=_blank>Plugin Description</a><br>" +
"This plugin provides support for backlog.<br>" +
"Features<br>" +
"<ul>" +
"<li>Add an issue</li>" +
"<li>Update an issue</li>" +
"<li>Create queries</li>" +
"<li>Find issues</li>" +
"<li>Schedules</li>" +
"<li>Resources</li>" +
"</ul>" +
"<a href=\"https://github.com/junichi11/Backlog4j\" target=_blank alt=\"go\">Backlog4j</a><br>" +
" </p>\n" +
"</html>\n",
"<html> \n" +
"Community Contributed Plugin<br>" +
" Version: 0.6.0<br>" +
"Author: junichi11(Junichi Yamamoto)<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-github-issues-plugin\">Plugin Description</a><br>" +
"This plugin provides support for GitHub Issue Tracker.<br>" +
"Features<br>" +
"<ul>" +
"<li>Create a new issue</li>" +
"<li>Edit an issue</li>" +
"<li>Create queries</li>" +
"<li>Edit an issue comment</li>" +
"<li>Delete an issue comment</li>" +
"<li>Create a new pull request</li>" +
"</ul>" +
"Change an existing issue to a pull request<br>" +
"Search issues with issue number or keywords<br>" +
"Create a new label<br>" +
"Create a new milestone<br>" +
"Set a schedule for an issue</html>\n",
"<html>\n" +
" <p style=\"margin-top: 0;\">Community Contributed Plugin<br>" +
"Version: 0.9.0<br>" +
"Author: Junichi Yamamoto<br>" +
"Date: 2020/6/21<br>" +
"Source: NetBeans Plugin Portal<br>" +
"Homepage: <a href=\"https://github.com/junichi11/netbeans-backlog-plugin\" target=_blank>Plugin Description</a><br>" +
"This plugin provides support for backlog.<br>" +
"Features<br>" +
"<ul>" +
"<li>Add an issue</li>" +
"<li>Update an issue</li>" +
"<li>Create queries</li>" +
"<li>Find issues</li>" +
"<li>Schedules</li>" +
"<li>Resources</li>" +
"</ul>" +
"<a href=\"https://github.com/junichi11/Backlog4j\" target=_blank alt=\"go\">Backlog4j</a><br>" +
" </p>\n" +
"</html>\n"
};
//table model
javax.swing.table.DefaultTableModel model = (javax.swing.table.DefaultTableModel) ((javax.swing.JTable)Form.getCurrentForm().getComponentByName("plugin_tb")).getModel();
model.setDataVector(dataVector, columnName);
//selectionListener
final javax.swing.ListSelectionModel listSelectionModel = new javax.swing.DefaultListSelectionModel();
javax.swing.event.ListSelectionListener selectionListener = new javax.swing.event.ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
String s = descr[listSelectionModel.getMaxSelectionIndex()];
((javax.swing.JEditorPane)Form.getCurrentForm().getComponentByName("Install_desc")).setText(s);
}
};
listSelectionModel.addListSelectionListener(selectionListener);
((javax.swing.JTable)Form.getCurrentForm().getComponentByName("plugin_tb")).setSelectionModel(listSelectionModel);
Form.getCurrentForm().getComponentByName("Check for Newest").setEnabled(false);
}
@Override
public void showPopupMenu(jswing.common.app.Application app, java.awt.Component invoker, java.awt.Point location){
if(invoker instanceof javax.swing.JTabbedPane) {
getJPopupMenu().removeAll();
JMenuItem menuItem1 = new JMenuItem("Close");
getJPopupMenu().add(menuItem1);
}
super.showPopupMenu(app, invoker, location);
}
@Override
public void propertyChange(java.awt.Component component){
if (component.equals(Form.getCurrentForm().getComponentByName("plugin_tb")) &&
((javax.swing.JTable)(component)).getEditingColumn() == 0) {
int row = ((javax.swing.JTable)(component)).getEditingRow();
boolean b = false;
if(((javax.swing.JTable)(component)).getValueAt(row, 0).equals(true)){
b = true;
} else {
int j = ((javax.swing.JTable)(component)).getRowCount();
for (int i = 0; i < j; i++){
if((((javax.swing.JTable)(component)).getValueAt(i, 0)) == null) {
}
else {
b = (Boolean)((javax.swing.JTable)(component)).getValueAt(i, 0);
if(b){
i = j;
}
}
}
}
((javax.swing.JButton)Form.getCurrentForm().getComponentByName("Install")).setEnabled(b);
}
}
@Override
public void hyperlinkUpdate(java.util.EventObject event) {
if (((javax.swing.event.HyperlinkEvent)event).getEventType() == javax.swing.event.HyperlinkEvent.EventType.ACTIVATED) {
try {
java.awt.Desktop.getDesktop().browse(((javax.swing.event.HyperlinkEvent)event).getURL().toURI());
} catch (java.io.IOException | java.net.URISyntaxException ex) {
ex.printStackTrace();
}
}
}
@Override
public void actionPerformed(java.awt.event.ActionEvent e){
String action = e.getActionCommand();
switch(action){
case "Help":
javax.swing.JOptionPane.showMessageDialog(null,
"Help",
"Dialog",
javax.swing.JOptionPane.INFORMATION_MESSAGE);
break;
case "Check for Newest":
tableInit();
break;
case "Select All":
setChoiceValue(((javax.swing.JTable)Form.getCurrentForm().getComponentByName("plugin_tb")),true);
break;
case "Deselect All":
setChoiceValue(((javax.swing.JTable)Form.getCurrentForm().getComponentByName("plugin_tb")),false);
break;
case "Install":
break;
case "Close":
((javax.swing.JTabbedPane)Form.getCurrentForm().getComponentByName("tabbedPane")).remove(((javax.swing.JTabbedPane)Form.getCurrentForm().getComponentByName("tabbedPane")).getSelectedIndex());
break;
case "Cancel":
System.exit(0);
}
}
private void setChoiceValue(javax.swing.JTable table, boolean b){
int j = table.getRowCount();
for(int i = 0; i < j; i ++){
if((table.getValueAt(i, 0)) == null) {
} else {
table.setValueAt(b, i, 0);
((javax.swing.JButton)Form.getCurrentForm().getComponentByName("Install")).setEnabled(b);
}
}
}
}
Code Explained
- ListSelectionListener
In this tutorial, we wish that shows the description of available plugins of the item, so we add a ListSelectionListener and an event handler named valueChanged and then show the information of the item if the item is selected.
- hyperlinkUpdate
In this tutorial, we use hyperlinkUpdate to get the URL address and open the URL in the default browser, the method named public void hyperlinkUpdate
Run the application
Press Ctrl-S to save the file, and press Shift-F6 to Run the application, and then you can right-click on the tabs to close it.
Exercises
- Redesign this application and make it can close tabs with buttons such as the following. You can get more references from Oracle Java Swing Tutorials.
Next steps
Click download source code or next for more tutorials.