我正在尝试创建一个组合框,以便我可以在弹出窗口中放置我喜欢的任何控件,在我的特定情况下是 JTree。看看 JComboBox 是如何实现的,弹出窗口实际上是由 UI 委托创建的。改变它的问题是它需要为每个外观和感觉重新实现,这是我不想做的事情......
我基本上想要一个组件,它具有 JComboBox 的外观和感觉(在当前外观中)并且弹出窗口是 JTree(在当前外观中)。
最简单的方法是什么?
JComboBox 本身不能做你想做的事。如果您绝对喜欢让它像 JComboBox 一样的概念,您可以让 JButton 在单击时弹出一个 JPanel。然后 JPanel 可以在其中包含您想要的任何内容(JTree 等)。
我已经尝试过制作可以做这样的事情的东西。
起初,我尝试按照 Varun 建议的方式实现一些东西,但事实证明它有点混乱,当我开始使用 ComponentUI 对象时我有点紧张(我宁愿把这种事情留给如果)。如果有人有这样做的好例子,我很想看看。
所以然后我尝试了按钮方法......并认为我会与 SO 社区分享代码:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.plaf.basic.BasicInternalFrameUI;
import javax.swing.plaf.metal.MetalComboBoxIcon;
public class MockJComboBox extends JPanel {
private boolean _isPoppedUp = false;
public MockJComboBox(String label, final JComponent toShow) {
setLayout(new BorderLayout());
JLabel jLabel = new JLabel(label);
jLabel.setBackground(Color.WHITE);
add(jLabel, BorderLayout.CENTER);
Icon icon = new MetalComboBoxIcon();
final JInternalFrame popup = new JInternalFrame(null, false, false, false, false);
final JPanel panel = new JPanel(new BorderLayout());
panel.add(new JScrollPane(toShow), BorderLayout.CENTER);
if(!(System.getProperty("os.name").startsWith("Mac OS"))){
BasicInternalFrameUI ui = (BasicInternalFrameUI) popup.getUI();
ui.getNorthPane().setPreferredSize(new Dimension(0,0));
}
popup.setBorder(null);
popup.setContentPane(panel);
popup.pack();
popup.setVisible(true);
final JButton dropDownButton = new JButton(icon);
dropDownButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
_isPoppedUp = !_isPoppedUp;
Container parent = getParent();
if (_isPoppedUp) {
popup.setLocation(panel.getX(), panel.getY() + panel.getHeight());
popup.setSize(panel.getWidth(), toShow.getHeight());
parent.add(popup);
} else {
parent.remove(popup);
parent.repaint();
}
}
});
add(dropDownButton, BorderLayout.EAST);
}
public boolean isPoppedUp() {
return _isPoppedUp;
}
}
如果您发现任何错误或对如何改进此代码有建议,我将不胜感激您的意见!
使用弹出带有 JTree 的 JPanel 的按钮的答案是正确的。针对 Carcassi 的评论,您可以使用自定义 TableCellRenderer 对其进行更改,使其看起来不像传统的按钮。
进一步的网络研究表明,自称为“专业的 Java 和 Swing 组件提供商”的Jidesoft生产了一个名为JIDE Grids的包,其中包括AbstractComboBox - 其描述表明它会这样做。
但是,这是一个付费套餐,我还没有尝试过......如果有人使用过这个,他们可以评论一下体验吗?
您只需要扩展 BasicComboBoxUI 然后覆盖所需的方法,例如
public static ComponentUI createUI( JComponent c)
和
protected ComboPopup createPopup()
创建自定义 ComboPopup 需要您在无法使用 BasicComboPopUp 的地方付出一些努力,因为它扩展了 JPopUpMenu
public class BasicComboPopup extends JPopupMenu implements ComboPopup
因此,在您的情况下,您可能希望扩展 JTree 并实现 ComboPopup。
我怀疑“改变它的问题是它需要为每个外观和感觉重新实现”部分。我不认为重新实施会有问题。
BasicComboPopup 在不同的外观和感觉上看起来不同,因为它是一个 JPopupMenu,而它又将具有 UI 委托。因此,如果您只是扩展 JTree,您应该不会遇到外观和感觉不同的问题。