2016-04-16 7 views
3

Ich versuche, eine JToggleButton aufzubauen, die eine JDialog (die eine JList enthält) zeigt, wenn die JToggleButton gedrückt wird. Und lassen Sie die JDialog verschwinden, wenn die JToggleButton erneut gedrückt wird, ODER wenn der Benutzer wegklickt oder woanders im Rahmen (ich simuliert dies über eine FocusListener auf der JList, wenn der Fokus verloren ist).Umgang mit Zustand und Ereignisfolgen von JDialog und JToggleButton

Wenn Sie die Taste nacheinander drücken, wird JDialog korrekt angezeigt und ausgeblendet.

Allerdings ist das Problem, wenn die JDialog sichtbar ist, und ich irgendwo anders auf den Rahmen klicken, verschwindet die JDialog korrekt, da der Fokus verloren geht. Der Status der JToggleButton bleibt jedoch falsch als ausgewählt festgelegt. Dies bedeutet, dass beim Klicken auf JToggleButton jetzt die JDialog nicht angezeigt wird, da der Status der JToggleButton jetzt nicht mehr synchron ist. Stattdessen muss ich zweimal die JToggleButton drücken, um die JDialog wieder sichtbar zu bekommen. Das folgende Codebeispiel veranschaulicht dieses Problem.

Ich kann nicht scheinen, den verlorenen Fokus der JList zu erhalten, um mit dem Zustand der JToggleButton zu synchronisieren. Es scheint ein einfaches Problem zu sein, aber ich stehe fest auf der Suche nach einer Lösung. Kann jemand helfen? Vielen Dank.

Sehen Sie meinen Code unten:

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

Antwort

1

Vorschläge:

  • Sie keine Action zum
  • JToggleButton hinzufügen, sondern eine ItemListener hinzuzufügen. Dies wird auf Änderungen im Auswahlstatus des Schalters reagieren.
  • Ändern Sie den sichtbaren Status des Dialogfelds in diesem Listener.
  • Ändern Sie in Ihrem FocusListener nicht den sichtbaren Status des Dialogfelds, sondern ändern Sie den Auswahlstatus des Schalters.
  • Verwenden Sie einen WindowFocusListener, der dem JDialog selbst hinzugefügt wird, um benachrichtigt zu werden, wenn er den Fokus verliert. Auf diese Weise kann der Listener-Code außerhalb des Codes für die Dialogkomponenten liegen, eine sauberere OOP-Lösung.

Zum Beispiel:

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

Danke für die Vorschläge, aber das ist leider immer noch ein Problem. Wenn Sie den Beispielcode verwenden, wird der 'JDialog' verschwinden, sobald der Fokus verloren ist, aber es führt zu einem neuen Problem, bei dem das Klicken auf den' JToggleButton' den 'JDialog' nun ständig sichtbar macht; anstelle des vorherigen Verhaltens, bei dem der 'JDialog' erscheint und verschwindet, wenn der' JToggleButton' jedes Mal ausgewählt oder nicht ausgewählt wird. – malaccan