2016-04-16 1 views
3

Я пытаюсь построить JToggleButton, который отображает JDialog (содержит JList), когда нажата кнопка JToggleButton. И при исчезновении JDialog, когда снова нажата кнопка JToggleButton, ИЛИ, если пользователь нажимает или где-то еще в кадре (я смоделировал это с помощью FocusListener на JList, когда фокус потерян).Обработка состояний и последовательностей событий JDialog и JToggleButton

Нажатие кнопки в последовательности отобразит и спрячет JDialog.

Однако проблема заключается в том, что видна JDialog, и я нажимаю в другом месте на рамке, JDialog правильно исчезает по мере того, как фокус теряется. Однако состояние JToggleButton остается некорректно заданным как выбранное. Это означало, что нажатие на JToggleButton теперь не отображает JDialog, так как состояние JToggleButton теперь не синхронизировано. Вместо этого мне нужно будет дважды нажать JToggleButton, чтобы снова увидеть JDialog. Мой пример кода ниже демонстрирует эту проблему.

Я не могу потерять фокус JList, чтобы синхронизироваться с состоянием JToggleButton. Это кажется простой проблемой, но я пытаюсь найти решение. Может ли кто-нибудь помочь? Благодарю.

Смотрите мой код ниже:

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 не изменяйте видимое состояние диалогового окна, а изменяйте состояние выбора переключателя.
  • Используйте WindowFocusListener, добавленный к самому JDialog, чтобы получать уведомление, если он теряет фокус. Таким образом, код слушателя может быть вне кода для компонентов диалога, более чистого решения 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

Смежные вопросы