bigleftie
bigleftie

Reputation: 453

How to prevent leaving a Tab on JTabbedPane

I have an application that has nested JTabbedPanes. Each of the JTabbedPanes include other JTabbedPanes.

I want to check something before allowing the user to leave the current tab.

When you run the code below, you'll see that the Months->February tab has an ALLOW checkbox.

If the ALLOW checkbox is selected, then I want to allow the user navigate to leave the current panel. If it is not, then they can't leave until it is.

I can't seem to find a way to handle the request to leave BEFORE the next Component (which may be on another JTabbedPane) is shown.

This can be demonstrated by going to the Months->February tab, and then selecting the Colors Tab.

Any ideas?

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

public class VerifyBeforeLeavingTab extends JFrame
{
    private static final long   serialVersionUID    = 1L;

    public VerifyBeforeLeavingTab()
    {
        setSize(700, 700);

        JTabbedPane mainTabbedPane = new JTabbedPane(JTabbedPane.TOP);

        MyJTabbedPane colorsPane = new MyJTabbedPane(JTabbedPane.TOP, "colors");
        JPanel bluePanel = new JPanel();
        bluePanel.setBackground(Color.blue);
        colorsPane.addTab("Blue", bluePanel);

        JPanel redPanel = new JPanel();
        redPanel.setBackground(Color.red);
        colorsPane.addTab("Red", redPanel);

        mainTabbedPane.addTab("Colors", colorsPane);

        JTabbedPane monthsPane = new MyJTabbedPane(JTabbedPane.TOP, "months");

        JPanel janPanel = new JPanel();
        monthsPane.addTab("January", janPanel);

        JPanel febPanel = new MyUnleavableJPanel();
        monthsPane.addTab("February", febPanel);

        mainTabbedPane.addTab("Months", monthsPane);

        add(mainTabbedPane, BorderLayout.CENTER);

        getContentPane().add(mainTabbedPane);
    }

    private class MyUnleavableJPanel extends JPanel
    {
        private static final long   serialVersionUID    = 1L;

        public MyUnleavableJPanel()
        {
            final JCheckBox chckBoxAllowToLeave = new JCheckBox("Allow to leave");
            chckBoxAllowToLeave.setBounds(100, 100, 50, 50);
            this.add(chckBoxAllowToLeave);

            addHierarchyListener(new HierarchyListener()
            {
                public void hierarchyChanged(HierarchyEvent e)
                {
                    if ((HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags()) != 0)
                    {
                        if (isShowing())
                        {
                            System.out.println("Showing an unleavable panel");
                        }
                        else
                        {
                            // TODO: Do not let them leave this JCheckbox is selected
                            if (chckBoxAllowToLeave.isSelected())
                            {
                                System.out.println("OK to leave");
                            }
                            else
                            {
                                System.out.println("Not allowed to leave");
                            }
                        }
                    }
                }
            });
        }
    }

    private class MyJTabbedPane extends JTabbedPane
    {
        private static final long   serialVersionUID    = 1L;

        public MyJTabbedPane(int i, String name)
        {
            super(i);
            setName(name);
        }

        @Override
        public void setSelectedIndex(int index)
        {
            System.out.println("Now on '" + getName() + "' tab #" + index);
            super.setSelectedIndex(index);
        }
    }

    private static void createAndShowGUI()
    {
        // Create and set up the window.
        VerifyBeforeLeavingTab frame = new VerifyBeforeLeavingTab();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    createAndShowGUI();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                    System.exit(0);
                }
            }
        });
    }

}

Upvotes: 2

Views: 2658

Answers (3)

bigleftie
bigleftie

Reputation: 453

@rcook - I have inserted your setSelected() method into my original code. When you run the program, the Blue panel (under Colors Tab) will be displayed.

If you go to the February Panel (under the Months Tab) you will see a Checkbox. This Checkbox is used to determine if the user should be able to leave the February panel.

Un-Select the Checkbox and then click on January. As expected, the user is not allowed to leave the panel.

Now, while the Checkbox is unselected, click on Colors. It does not work - the user should not have been able to leave the February panel because the checkbox was not checked.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

public class VerifyBeforeLeavingTab extends JFrame
{
    private static final long       serialVersionUID    = 1L;
    private static final JCheckBox  chckBoxAllowToLeave = new JCheckBox("Allow to leave");

    public VerifyBeforeLeavingTab()
    {
        setSize(700, 700);

        JTabbedPane mainTabbedPane = new JTabbedPane(JTabbedPane.TOP);

        MyJTabbedPane colorsPane = new MyJTabbedPane(JTabbedPane.TOP, "colors");
        JPanel bluePanel = new JPanel();
        bluePanel.setBackground(Color.blue);
        colorsPane.addTab("Blue", bluePanel);

        JPanel redPanel = new JPanel();
        redPanel.setBackground(Color.red);
        colorsPane.addTab("Red", redPanel);

        mainTabbedPane.addTab("Colors", colorsPane);

        JTabbedPane monthsPane = new MyJTabbedPane(JTabbedPane.TOP, "months");

        JPanel janPanel = new JPanel();
        monthsPane.addTab("January", janPanel);

        JPanel febPanel = new MyUnleavableJPanel();
        monthsPane.addTab("February", febPanel);

        mainTabbedPane.addTab("Months", monthsPane);

        add(mainTabbedPane, BorderLayout.CENTER);

        getContentPane().add(mainTabbedPane);
    }

    private class MyUnleavableJPanel extends JPanel
    {
        private static final long   serialVersionUID    = 1L;

        public MyUnleavableJPanel()
        {
            // final JCheckBox chckBoxAllowToLeave = new JCheckBox("Allow to leave");
            chckBoxAllowToLeave.setBounds(100, 100, 50, 50);
            chckBoxAllowToLeave.setSelected(true);
            this.add(chckBoxAllowToLeave);

            addHierarchyListener(new HierarchyListener()
            {
                public void hierarchyChanged(HierarchyEvent e)
                {
                    if ((HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags()) != 0)
                    {
                        if (isShowing())
                        {
                            System.out.println("Showing an unleavable panel");
                        }
                        else
                        {
                            // TODO: Do not let them leave if this JCheckbox is selected
                            if (chckBoxAllowToLeave.isSelected())
                            {
                                System.out.println("OK to leave");
                            }
                            else
                            {
                                System.out.println("Not allowed to leave");
                            }
                        }
                    }
                }
            });
        }
    }

    private class MyJTabbedPane extends JTabbedPane
    {
        private static final long   serialVersionUID    = 1L;

        public MyJTabbedPane(int i, String name)
        {
            super(i);
            setName(name);
        }

        /**
         * override of selecting a new panel; the new panel selection is only allowed after the current panel determines
         * that its data is valid.
         */
        @Override
        public void setSelectedIndex(int newIndex)
        {
            System.out.println("Now on '" + getName() + "' tab #" + newIndex);
            int currentIndex = getSelectedIndex();
            if (newIndex >= 0 && newIndex < getTabCount())
            {
                // if we are currently setting the selected tab for the first
                // time, we don't need to validate the currently selected panel;
                // same if we're (somehow) selecting the current panel
                if (currentIndex == -1)
                {
                    super.setSelectedIndex(newIndex);
                }
                else
                {
                    if (currentIndex != newIndex)
                    {
                        if (chckBoxAllowToLeave.isSelected())
                        {
                            super.setSelectedIndex(newIndex);
                        }
                        else
                        {
                            JOptionPane.showMessageDialog(null, "Not this time");
                        }

                    }
                }
            }
            else
            {
                System.out.println("setting new tabbed pane index to " + newIndex + "; wonder why?");
            }
        }
    }

    private static void createAndShowGUI()
    {
        // Create and set up the window.
        VerifyBeforeLeavingTab frame = new VerifyBeforeLeavingTab();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    createAndShowGUI();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                    System.exit(0);
                }
            }
        });
    }

}

Upvotes: 0

arcy
arcy

Reputation: 13103

Ok, decided to go ahead with my own example; two classes, running the main class produces a swing window that allows you to change tabs every other time you click.

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

    public class TabbedPaneExample extends JFrame
    {
        public static void main(String[] args)
        {
            TabbedPaneExample example = new TabbedPaneExample();
            example.go();
        }

        public void go()
        {
            ValidatingTabbedPane vtp = new ValidatingTabbedPane();
            for(int i=0; i<3; i++)
            {
                vtp.addTab(""+i, new JPanel());
            }
            vtp.setSelectedIndex(0);

            getContentPane().add(vtp);
            pack();
            setVisible(true);
        }
    }

and the other class:

    import javax.swing.JOptionPane;
    import javax.swing.JTabbedPane;

    public class ValidatingTabbedPane extends JTabbedPane
    {
      private static final long serialVersionUID = 1L;
      private static void debug(String msg) { System.out.println(msg); }
      private static boolean thisTime = true;

      /**
       * override of selecting a new panel; the new panel selection
       * is only allowed after the current panel determines that
       * its data is valid.
       */
        @Override
        public void setSelectedIndex(int newIndex)
        {
            int currentIndex = getSelectedIndex();
            if (newIndex >=0 && newIndex < getTabCount())
            {
                // if we are currently setting the selected tab for the first
                // time, we don't need to validate the currently selected panel;
                // same if we're (somehow) selecting the current panel
                if(currentIndex == -1)
                {
                    super.setSelectedIndex(newIndex);
                }
          else
          {
              if (currentIndex != newIndex)
              {
                if (thisTime)
                {
                    super.setSelectedIndex(newIndex);
                }
                else
                {
                    JOptionPane.showMessageDialog(null, "Not this time");
                }
                thisTime = !thisTime;
                // ok, the user wants to go from one panel to another.
                // ensure there are no validation errors on the current
                // panel before he moves on.
    //          DataPanel panel = (DataPanel) getSelectedComponent();
    //          if (panel.validateData())
    //          {
    //              super.setSelectedIndex(newIndex);
    ////                tabChangeListener.tabsChanged();
    //          }
            }
          }
            }
            else
            {
                debug("setting new tabbed pane index to " + newIndex + "; wonder why?");
            }
        }



    }

I left comments in to show where I'm validating in my real program.

Upvotes: 1

arcy
arcy

Reputation: 13103

I extended JTabbedPane and overrode setSelectedIndex(). If you want to allow the selection to succeed, call super.setSelectedIndex; otherwise don't.

I use this to call a validation routine associated with the tab, and veto the change if validation fails. One nice thing about this method is that it is not at all dependent on how the user changes tabs -- he could click on a tab, click a button that moves tabs, etc.

Upvotes: 3

Related Questions