Close tabs in TabPane dynamically

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:

  1. Familiar with Java swing development. Go to Oracle Java Swing to get the tutorial.
  2. Familiar with the first three tutorials on JSwing.
  3. Familiar with the Operation of Apache NetBeans.
  4. Familiar with the timing and object of ListSelectionListener and hyperlinkUpdate get called.

 

Create a Form

  1. 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.

    CloseableJTabbedPane tree-view

  2. Change the properties of the components as shown in the table below.
    ComponentstextactionCommandname
    jButton1CancelCancelCancel
    jButton2HelpHelpHelp
    jButton3Check for NewestCheck for NewestCheck for Newest
    jButton4InstallInstallInstall
    jButton5Select AllSelect AllSelect All
    jButton6Deselect AllDeselect AllDeselect All
    jTabbedPane1  tabbedPane
    jTable1  plugin_tb
    jEditorPane1  Install_desc
  3. 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.

    CloseableJTabbedPane Form

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

  1. 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.

  2. 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.

CloseableJTabbedPane

 

Exercises

  1. 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.

    TabComponentsDemo

Next steps

Click download source code or next for more tutorials.

Share this page

Let more people know about this site, please share