2012-01-22 72 views
2

我有一個嵌套了JTabbedPanes的應用程序。每個JTabbedPanes包含其他JTabbedPanes。如何防止在JTabbedPane上留下選項卡

我想在允許用戶離開當前選項卡之前檢查一些內容。

當您運行下面的代碼時,您會看到Months-> February選項卡上有一個ALLOW複選框。

如果允許複選框被選中,那麼我想允許用戶導航離開當前面板。如果不是,那麼他們不能離開,直到它。

我似乎無法找到一種方法來處理請求離開之前下一個組件(可能在另一個JTabbedPane)顯示。

這可以通過轉到Months-> February選項卡,然後選擇顏色選項卡來演示。

任何想法?

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); 
       } 
      } 
     }); 
    } 

} 
+0

另請參閱此[答案](http://stackoverflow.com/a/2016686/230513)。 – trashgod

回答

3

我擴展了JTabbedPane並覆蓋了setSelectedIndex()。如果您想允許選擇成功,請調用super.setSelectedIndex;否則不要。

我用它來調用與該選項卡關聯的驗證例程,並在驗證失敗時否決更改。這種方法的一個好處是,它根本不依賴於用戶如何更改標籤 - 他可以點擊標籤,單擊移動標籤的按鈕等。

+0

rcook,問題是setSelectedIndex()在要顯示的選項卡上被調用,而不是在被選中的選項卡上。在我的代碼中,我有兩個JTabbedPanes,當點擊另一個JTabbedPane中的選項卡時發生問題。具體來說,如果您在BLUE選項卡上並點擊MONTH。 setSelectedIndex()將在MONTH中的可見選項卡上調用,而不是COLORS。這並不能解決我的問題。 – bigleftie

+0

我已經這樣做了,我認爲它確實可以解決您的問題。setSelectedIndex被調用,索引被設置爲;在你的例子中,傳遞給setSelectedIndex的int將對應MONTH,並且那裏的getSelectedIndex將返回BLUE。如果你沒有在你的實現中調用super.setSelectedIndex,那麼選擇不會改變。如果你發現它不起作用併發布SSCE,我會試着弄清楚爲什麼我的工作和你的工作沒有。但我重複一遍,我已經這樣做了。 – arcy

1

好吧,決定繼續我的自己的例子;兩個類,運行主類產生一個揮杆窗口,允許你每次點擊時改變選項卡。

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); 
     } 
    } 

和其他類:

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?"); 
      } 
     } 



    } 

我離開的意見中顯示,其中我在實際的程序正在驗證。

+0

這適用於在同一個JTabbedPane中的選項卡之間進行策略導航。但是,它不能解決我的問題。我在下面發佈了代碼來演示我的問題(包括您的一些代碼)。 – bigleftie

0

@rcook - 我已經將你的setSelected()方法插入到我的原始代碼中。 當您運行該程序時,將顯示藍色面板(在顏色標籤下)。

如果您轉到二月面板(在月份選項卡下),您將看到一個複選框。該複選框用於確定用戶是否應該能夠離開2月面板。

取消選中複選框,然後單擊一月。正如所料,用戶不允許離開面板。

現在,雖然複選框未被選中,但單擊顏色。它不起作用 - 用戶不應該離開2月面板,因爲複選框沒有被選中。

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); 
       } 
      } 
     }); 
    } 

} 
+0

好吧,你現在有嵌套的標籤面板,這是一個稍微不同的情況。如果您在該選項卡式窗格*上選擇不同的面板,我認爲您只能「離開」面板。所以我認爲它按照設計工作。如果要防止如果選擇2月並且未選中該框時離開「月」面板,則需要覆蓋「mainTabbedPane」中的setSelectedIndex並確定是否希望用戶能夠在此處進行更改。 – arcy

+0

實際上,如果「外部」選項卡窗格的每個面板都是JPanel的擴展,並且它也實現了類似「okToLeave()」的方法,則外部選項卡式窗格setSelectedIndex()可以查詢當前選定的面板以查看是否沒關係走開;這可以節省您將內部選項卡式窗格邏輯放置在外部選項卡式窗格中。 – arcy

相關問題