2012-01-22 15 views
2

私はJTabbedPanesをネストしたアプリケーションを持っています。各JTabbedPaneには、他のJTabbedPaneが含まれています。JTabbedPaneにタブを残さないようにする方法

ユーザーが現在のタブから離れることを許可する前に、何かを確認したいと思います。

次のコードを実行すると、[月] - [2月]タブに[許可]チェックボックスが表示されます。

[許可]チェックボックスをオンにすると、ユーザーが現在のパネルを離れてナビゲートできるようにします。そうでなければ、彼らはそれができるまで残すことができません。

次のコンポーネント(別のJTabbedPane上にある可能性があります)が表示される前に、そのリクエストを処理する方法が見つからないようです。

これは、[月] - [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.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を呼び出します。それ以外はしないでください。

私はこれを使用して、タブに関連付けられた検証ルーチンを呼び出し、検証が失敗した場合に変更を拒否します。この方法の良い点の1つは、ユーザーがタブをどのように変更するかに依存しないことです。タブをクリックするか、タブを移動するボタンをクリックするなどです。

+0

rcook、setSelectedIndex()は表示されるタブで呼び出され、残っているタブでは呼び出されません。私のコードでは、2つのJTabbedPaneがあり、別のJTabbedPaneのタブをクリックすると問題が発生します。具体的には、BLUEタブをクリックしてMONTHをクリックした場合。 setSelectedIndex()は、COLORSではなくMONTHの可視タブで呼び出されます。これは私の問題を解決しません。 – bigleftie

+0

私はすでにこれをやっており、あなたの問題を解決すると思います。インデックスが設定されている状態でsetSelectedIndexが呼び出されます。あなたの例では、setSelectedIndexに渡されるintはMONTHに対応し、getSelectedIndexはBLUEに対応するgetSelectedIndexを返します。実装でsuper.setSelectedIndexを呼び出さないと、選択は変更されません。それがうまく動作せず、SSCEを投稿した場合、私はなぜ私の作品があなたのものではないのか理解しようとします。しかし私は繰り返す、私はすでにこれを行う。 – arcy

1

Ok、自分の例。メインクラスを実行する2つのクラスはスイングウィンドウを生成し、クリックするたびにタブを変更できます。

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月のパネルを離れることができるかどうかを判断するために使用されます。

チェックボックスをオフにして、[1月]をクリックします。予想どおり、ユーザーはパネルを離れることはできません。

チェックボックスを選択していない状態で、[色]をクリックします。それは機能しません - チェックボックスがチェックされていないため、ユーザーは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