尝试使用一些"黑暗的一面"当我尝试使用某些组件填充组合框的弹出框时,Swing的功能和问题。这是我的SSCCE:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.ComboPopup;
public class ComboBoxTryout extends JComboBox {
private JPanel panel;
public ComboBoxTryout() {
initPanel();
}
private void initPanel() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
setPopupComponent(this, panel);
}
private JCheckBox createCheckBox(String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
getModel().setSelectedItem(b.toString());
}
});
return cb;
}
/**
* Sets the custom component as popup component for the combo-box.
*
* @param combo combo-box to get new popup component.
* @param comp new popup component.
*/
public static void setPopupComponent(JComboBox<?> combo, Component comp) {
final ComboPopup popup = (ComboPopup) combo.getUI().getAccessibleChild(combo, 0);
if (popup instanceof Container) {
Container c = (Container) popup;
c.removeAll();
c.setLayout(new GridLayout(1, 1));
c.add(comp);
c.setPreferredSize(comp.getPreferredSize());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frm = new JFrame("Test");
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
frm.setSize(250, 600);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
});
}
}
我可以打开组合框但是当我单击弹出窗口中的复选框时,组合框将关闭,但仍未选中复选框。但是,当我改变行
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
到
frm.add(new ComboBoxTryout(), BorderLayout.SOUTH);
一切正常:我可以更改复选框的状态,弹出窗口仍然可见!任何建议,如何让它适用于BorderLayout.NORTH
?
答案 0 :(得分:1)
以下内容并未使用常规JComboBox
,而是模仿其中一项,以便为您提供更多控制权。
此示例的灵感来自Creating Pop-Up Components 和您的代码。
它在按钮和文本字段上使用Popup
组件和侦听器(textfield +按钮看起来像一个组合框,此部分在此示例中未进行视觉优化)来管理弹出窗口隐藏/显示。 / p>
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingConstants;
public class ButtonPopupSample {
private final JTextField tField;
private final JButton start;
private final JPanel panel;
private boolean popping = false;
private Popup popup;
ButtonPopupSample() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
JFrame frame = new JFrame("Button Popup Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tField = new JTextField(20);
tField.setEditable(false);
start = new JButton("Pop");
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
popOrNot();
}
};
start.addActionListener(actionListener);
tField.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent me) {
popOrNot();
}
});
JPanel contPan = new JPanel();
contPan.add(tField);
contPan.add(start);
frame.setContentPane(contPan);
frame.setSize(350, 250);
frame.setVisible(true);
}
private JCheckBox createCheckBox(final String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
tField.setText(b.toString());
}
});
return cb;
}
private void popOrNot() {
if (popping) {
popup.hide();
} else {
PopupFactory factory = PopupFactory.getSharedInstance();
Point location = tField.getLocationOnScreen();
popup = factory.getPopup(tField, panel, location.x, location.y + tField.getHeight());
popup.show();
}
popping = !popping;
}
public static void main(final String args[]) {
new ButtonPopupSample();
}
}
答案 1 :(得分:1)
找到解决方案。奇怪的焦点改变事件提供了上述问题。因此必须防止对此事件的处理。
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DateFormatSymbols;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.ComboPopup;
@SuppressWarnings("serial")
public class ComboBoxTryout extends JComboBox {
private JPanel panel;
private boolean avoidFocusChange;
/**
*
*/
public ComboBoxTryout() {
initPanel();
}
private void initPanel() {
panel = new JPanel(new GridLayout(7, 1, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
DateFormatSymbols symbols = new DateFormatSymbols();
for (String s : symbols.getWeekdays()) {
if (s != null && !s.trim().isEmpty()) {
panel.add(createCheckBox(s));
}
}
setPopupComponent(this, panel);
}
@Override
protected void processFocusEvent(FocusEvent e) {
if (avoidFocusChange && FocusEvent.FOCUS_LOST == e.getID() && panel.isAncestorOf(e.getOppositeComponent())) {
System.out.println(e); // skip it
} else {
super.processFocusEvent(e);
}
avoidFocusChange = false;
}
private JCheckBox createCheckBox(String text) {
final JCheckBox cb = new JCheckBox(text);
cb.setHorizontalAlignment(SwingConstants.LEADING);
cb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StringBuilder b = new StringBuilder();
for (Component c : panel.getComponents()) {
if (c instanceof JCheckBox && ((JCheckBox) c).isSelected()) {
if (b.length() > 0) {
b.append(", ");
}
b.append(((JCheckBox) c).getText().substring(0, 3));
}
}
getModel().setSelectedItem(b.toString());
}
});
cb.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
avoidFocusChange = SwingUtilities.isLeftMouseButton(e);
}
});
return cb;
}
/**
* Sets the custom component as popup component for the combo-box.
*
* @param combo combo-box to get new popup component.
* @param comp new popup component.
*/
public static void setPopupComponent(JComboBox<?> combo, Component comp) {
final ComboPopup popup = (ComboPopup) combo.getUI().getAccessibleChild(combo, 0);
if (popup instanceof Container) {
Container c = (Container) popup;
c.removeAll();
c.setLayout(new GridLayout(1, 1));
c.add(comp);
Dimension dim = comp.getPreferredSize();
dim.width += 10; // need 10 px more width
c.setPreferredSize(dim);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frm = new JFrame("Test");
frm.add(new ComboBoxTryout(), BorderLayout.NORTH);
frm.setSize(250, 600);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
});
}
}
如果有人找到更好的解决方案,请发帖!!!