Обработка состояний и последовательностей событий JDialog и JToggleButton
Я пытаюсь построить JToggleButton
который отображает JDialog
(который содержит JList
) когда JToggleButton
нажата. И есть JDialog
исчезают, когда JToggleButton
нажимается снова, ИЛИ, если пользователь щелкает или где-то еще в кадре (я смоделировал это с помощью FocusListener
на JList
когда фокус потерян).
Последовательное нажатие кнопки отобразит и скроет 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, чтобы получать уведомления, если он теряет фокус. Таким образом, код слушателя может находиться за пределами кода для компонентов диалога, что является более чистым решением ООП.
Например:
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);
}
}