2016-04-16 83 views
3

我試圖構建一個JToggleButton,它在按下JToggleButton時顯示JDialog(包含JList)。當JToggleButton再次被按下時,或JDialog消失,或者如果用戶點擊走開或在框架中的其他地方(我在失去焦點時通過FocusListener上的FocusListener進行模擬)。處理JDialog和JToggleButton的狀態和事件序列

按順序按下將顯示並正確隱藏JDialog

但是,問題是當JDialog可見時,我點擊框架上的其他地方,JDialog正確消失,因爲焦點丟失。但是,JToggleButton的狀態仍未正確設置爲選中狀態。這意味着現在單擊JToggleButton將不會顯示JDialog,因爲JToggleButton的狀態現在不同步。相反,我需要按JToggleButton兩次才能使JDialog再次可見。我下面的代碼示例演示了這個問題。

我似乎無法得到JListJToggleButton的狀態同步失去焦點。這似乎是一個簡單的問題,但我試圖找到解決方案。誰能幫忙?謝謝。

見下面我的代碼:

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

建議:

  • 一個ActionListener不要再增加對JToggleButton
  • 而是添加一個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