如何自定义JComboBox以使弹出窗口是JTree(而不是列表)?

时间:2009-11-24 16:25:01

标签: java swing popup jtree jcombobox

我正在尝试创建一个组合框,以便我可以在弹出窗口中放置我喜欢的任何控件,在我的特定情况下是一个JTree。看看JComboBox是如何实现的,弹出窗口实际上是由UI委托创建的。改变这个问题的方法是需要为每个外观重新实现,这是我不想做的事情......

我基本上想要一个具有JComboBox外观和感觉的组件(在当前的外观中),弹出窗口是一个JTree(在当前的外观中)。

最简单的方法是什么?

5 个答案:

答案 0 :(得分:2)

JComboBox本身无法做到你想要的。如果你完全坚持让它像JComboBox一样的概念,你可以让JButton在点击时弹出一个JPanel。然后JPanel可以拥有你想要的任何东西(JTree,等等)。

答案 1 :(得分:1)

我已经开始制作可以做这样的事了。

起初,我试图按照Varun建议的方式实现一些东西,但事实证明它有点混乱,当我开始玩ComponentUI对象时我有点紧张(我宁愿离开那种L& F)的事情。如果有人有这样做的好例子,我有兴趣看到它。

然后我尝试了按钮方法......并且认为我会与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;
  }
}

如果您发现任何错误或有关如何改进此代码的建议,我将非常感谢您的评论!

答案 2 :(得分:0)

您只需要扩展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,那么您应该不会遇到不同外观的问题。

答案 3 :(得分:0)

使用弹出带有JTree的JPanel的按钮的答案是正确的。为了回应Carcassi的评论,您可以使用自定义TableCellRenderer进行更改,使其看起来不像传统按钮。

答案 4 :(得分:0)

进一步的网络研究显示,Jidesoft,他们称自己为“专业的Java和Swing组件提供商”,会生成一个名为JIDE Grids的软件包,其中包含AbstractComboBox - 其描述建议它会这样做。

然而,这是一个付费的套餐,我没有尝试过......如果有人使用过它,他们可以评论一下这个经历吗?