2016-04-16 15 views
3

JToggleButtonが押されたときにJDialogJListを含む)を表示するJToggleButtonを構築しようとしています。 JToggleButtonが再び押されたとき、またはユーザーがフレーム内の他の場所をクリックすると、JDialogが消えます(フォーカスが失われたときに私はFocusListenerJListでこれをシミュレートしました)。JDialogとJToggleButtonの状態とイベントシーケンスを処理する

ボタンを順番に押すと、JDialogが正しく表示され、非表示になります。

しかし、JDialogが表示され、フレーム上の別の場所をクリックすると、フォーカスが失われたときにJDialogが正しく表示されなくなるという問題があります。ただし、JToggleButtonの状態は誤って選択されたままになります。これは、今すぐJToggleButtonの状態が同期していないので、JToggleButtonをクリックするとJDialogが表示されないことを意味します。代わりにJToggleButtonを2回押してJDialogを再び表示させる必要があります。以下のコード例は、この問題を示しています。

の状態で、JListの同期が失われているとは思えません。それは簡単な問題のようですが、解決策を見つけようとしています。誰も助けることができますか?ありがとう。

は、以下の私のコードを参照してください:

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.FocusEvent; 
import java.awt.event.FocusListener; 

public class MultiComboBox extends JToggleButton 
{ 
    public MultiComboBox(JFrame frame, String buttonText) 
    { 
     super(buttonText); 

     JDialog dialog = new JDialog(frame, false); 
     dialog.setLayout(new BorderLayout()); 

     Object[] items = new Object[] { "one", "two", "three" }; 
     JList list = new JList(items); 
     list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 

     JScrollPane listScrollPane = new JScrollPane(list, 
      JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
      JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
     listScrollPane.setPreferredSize(list.getPreferredSize()); 

     dialog.add(listScrollPane, BorderLayout.CENTER); 
     dialog.pack(); 

     addActionListener(new ActionListener() 
     { 
      @Override 
      public void actionPerformed(ActionEvent e) 
      { 
       final JToggleButton button = (JToggleButton) e.getSource(); 
       System.out.println("button clicked: " + button.isSelected()); 
       if (button.isSelected()) 
       { 
        Point p = button.getLocation(); 
        p.setLocation(p.getX() + 300, p.getY()); 
        SwingUtilities.convertPointToScreen(p, button); 
        dialog.setLocation(p); 
        dialog.setVisible(true); 
       } 
       else 
        dialog.setVisible(false); 
      } 
     }); 

     list.addFocusListener(new FocusListener() 
     { 
      @Override 
      public void focusGained(FocusEvent e) 
      { 
      } 

      @Override 
      public void focusLost(FocusEvent e) 
      { 
       System.out.println("list focusLost, dialog: " + dialog.isVisible()); 
       dialog.setVisible(false); 
      } 
     }); 
    } 

    public static void main(String[] args) 
    { 
     JFrame frame = new JFrame("Test"); 
     frame.setPreferredSize(new Dimension(300, 300)); 
     frame.setLayout(new BorderLayout()); 

     MultiComboBox mcb = new MultiComboBox(frame, "Toggle"); 

     JPanel buttonPanel = new JPanel(new BorderLayout()); 
     buttonPanel.setPreferredSize(new Dimension(80, 30)); 
     buttonPanel.add(mcb, BorderLayout.CENTER); 

     JPanel blankPanel = new JPanel(new BorderLayout()); 
     frame.add(blankPanel, BorderLayout.CENTER); 

     frame.add(buttonPanel, BorderLayout.PAGE_START); 
     frame.pack(); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    } 
} 

答えて

1

提案:

  • はJToggleButton
  • にActionListenerを追加しますが、その代わりのItemListenerを追加しないでください。これは、トグルの選択状態の変更に応答します
  • このリスナーの内部で、ダイアログの可視状態を変更します。
  • FocusListenerでは、ダイアログの可視状態を変更せず、トグルの選択状態を変更します。
  • JDialog自体に追加されたWindowFocusListenerを使用して、フォーカスを失った場合に通知されます。このようにして、リスナーコードは、よりクリーンなOOPソリューションであるダイアログコンポーネントのコードの外に置くことができます。たとえば、

import javax.swing.*; 

import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.FocusEvent; 
import java.awt.event.FocusListener; 
import java.awt.event.ItemEvent; 
import java.awt.event.ItemListener; 

public class MultiComboBox2 extends JToggleButton { 
    public MultiComboBox2(JFrame frame, String buttonText) { 
     super(buttonText); 

     JDialog dialog = new JDialog(frame, false); 
     dialog.setLayout(new BorderLayout()); 

     Object[] items = new Object[] { "one", "two", "three" }; 
     JList list = new JList(items); 
     list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 

     JScrollPane listScrollPane = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
       JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
     listScrollPane.setPreferredSize(list.getPreferredSize()); 

     dialog.add(listScrollPane, BorderLayout.CENTER); 
     dialog.pack(); 

     addItemListener(new ItemListener() { 

      @Override 
      public void itemStateChanged(ItemEvent e) { 
       final JToggleButton button = (JToggleButton) e.getSource(); 
       if (e.getStateChange() == ItemEvent.SELECTED) { 
        Point p = button.getLocation(); 
        p.setLocation(p.getX() + 300, p.getY()); 
        SwingUtilities.convertPointToScreen(p, button); 
        dialog.setLocation(p); 
        dialog.setVisible(true); 
       } else { 
        dialog.setVisible(false); 
       } 
      } 
     }); 
     // addActionListener(new ActionListener() { 
     // @Override 
     // public void actionPerformed(ActionEvent e) { 
     // final JToggleButton button = (JToggleButton) e.getSource(); 
     // System.out.println("button clicked: " + button.isSelected()); 
     // if (button.isSelected()) { 
     // Point p = button.getLocation(); 
     // p.setLocation(p.getX() + 300, p.getY()); 
     // SwingUtilities.convertPointToScreen(p, button); 
     // dialog.setLocation(p); 
     // dialog.setVisible(true); 
     // } else 
     // dialog.setVisible(false); 
     // } 
     // }); 

     list.addFocusListener(new FocusListener() { 
      @Override 
      public void focusGained(FocusEvent e) { 
      } 

      @Override 
      public void focusLost(FocusEvent e) { 
       System.out.println("list focusLost, dialog: " + dialog.isVisible()); 
       // dialog.setVisible(false); 
       MultiComboBox2.this.setSelected(false); 
      } 
     }); 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame("Test"); 
     frame.setPreferredSize(new Dimension(300, 300)); 
     frame.setLayout(new BorderLayout()); 

     MultiComboBox2 mcb = new MultiComboBox2(frame, "Toggle"); 

     JPanel buttonPanel = new JPanel(new BorderLayout()); 
     buttonPanel.setPreferredSize(new Dimension(80, 30)); 
     buttonPanel.add(mcb, BorderLayout.CENTER); 

     JPanel blankPanel = new JPanel(new BorderLayout()); 
     frame.add(blankPanel, BorderLayout.CENTER); 

     frame.add(buttonPanel, BorderLayout.PAGE_START); 
     frame.pack(); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    } 
} 
+0

提案をお寄せいただきありがとうございますが、残念ながらこれはまだ問題です。サンプルコードを使用すると、フォーカスが失われると 'JDialog'が消えますが、' JToggleButton'をクリックすると 'JDialog'が常に表示されるようになりました。以前の動作ではなく、 'JDialog'が現れ、' JToggleButton'が選択/選択解除されるたびに消えます。 – malaccan

関連する問題