Java 处理JDialog和JToggleButton的状态和事件序列
我试图构建一个Java 处理JDialog和JToggleButton的状态和事件序列,java,swing,jdialog,jtogglebutton,focuslistener,Java,Swing,Jdialog,Jtogglebutton,Focuslistener,我试图构建一个JToggleButton,当按下JToggleButton时,它会显示一个JDialog(其中包含一个JList)。当再次按下JToggleButton时,或者如果用户在画面中的某个地方或远处单击时,让JDialog消失(当焦点丢失时,我通过JList上的FocusListener模拟) 按顺序按下按钮将正确显示和隐藏JDialog 但是,问题是当JDialog可见时,我单击帧上的其他位置,焦点丢失时JDialog会正确地消失。但是,JToggleButton的状态仍然错误地设置
JToggleButton
,当按下JToggleButton
时,它会显示一个JDialog
(其中包含一个JList
)。当再次按下JToggleButton
时,或者如果用户在画面中的某个地方或远处单击时,让JDialog
消失(当焦点丢失时,我通过JList
上的FocusListener
模拟)
按顺序按下按钮将正确显示和隐藏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);
}
}
建议:
- 不要将ActionListener添加到JToggleButton
- 而是添加一个ItemListener。这将响应切换选择状态的更改
- 在此侦听器中,更改对话框的可见状态
- 在FocusListener中,不要更改对话框的可见状态,而是更改切换的选择状态
- 使用添加到JDialog本身的WindowFocusListener,在其失去焦点时收到通知。通过这种方式,侦听器代码可以位于对话框组件的代码之外,这是一种更干净的OOPs解决方案
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);
}
}
谢谢你的建议,但不幸的是,这仍然是一个问题。使用示例代码,
JDialog
会在焦点丢失后消失,但它引入了一个新问题,单击JToggleButton
会使JDialog
始终可见;而不是以前的行为,每次选择/取消选择JToggleButton
时,JDialog
会出现并消失。