简体   繁体   English

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

[英]How do I customize a JComboBox so that the pop-up is a JTree (instead of a list)?

I am trying to create a combo box so that I can put whatever control I prefer within the pop-up, in my specific case a JTree. 我正在尝试创建一个组合框,以便我可以在弹出窗口中放置我喜欢的任何控件,在我的特定情况下是JTree。 Having a look at how the JComboBox is implement, the pop-up is really created by the UI delegate. 看看JComboBox是如何实现的,弹出窗口实际上是由UI委托创建的。 The problem in changing that is that it would need to be re-implemented for each look and feel, which is something I do not want to do... 改变这个问题的方法是需要为每个外观重新实现,这是我不想做的事情......

I basically want a component that it has the look and feel of a JComboBox (in the current look and feel) and the popup is a JTree (in the current look and feel). 我基本上想要一个具有JComboBox外观和感觉的组件(在当前外观中),弹出窗口是一个JTree(在当前外观中)。

What's the easiest way to do that? 最简单的方法是什么?

JComboBox itself can't do what you want. JComboBox本身无法做到你想要的。 If you're absolutely wedded to the concept of having it act like a JComboBox, you could make a JButton pop up a JPanel on click. 如果你完全坚持让它像JComboBox一样的概念,你可以让JButton在点击时弹出一个JPanel。 Then the JPanel could have whatever you want inside it (JTree, etcetera). 然后JPanel可以拥有你想要的任何东西(JTree,等等)。

I've had a go at producing something that would do something like this. 我已经开始做一些可以做这样的事了。

At first, I tried to implement something along the lines suggested by Varun, but it was proving to be a bit messy, and I get a little nervous when I start playing with ComponentUI objects (I'd rather leave that sort of thing to the L&F). 起初,我尝试按照Varun建议的方式实现一些东西,但事实证明它有点混乱,当我开始玩ComponentUI对象时,我有点紧张(我宁愿把那种事情留给如果)。 If anyone has a good example of doing this, I'd be interested to see it. 如果有人有这样做的好例子,我有兴趣看到它。

So then I tried the button approach... and thought I would share the code with the SO community: 那么我尝试了按钮方法......并且认为我将与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;
  }
}

If you spot any bugs or have suggestions on how to improve this code, I'd be grateful for your comments! 如果您发现任何错误或有关如何改进此代码的建议,我将不胜感激您的意见!

Further web research revealed that Jidesoft , who describe themselves as "a professional Java and Swing component provider" produce a package called JIDE Grids , which includes AbstractComboBox - the description for which suggests it would do this. 进一步的网络研究显示,自称为“专业Java和Swing组件提供商”的Jidesoft生产了一个名为JIDE Grids的软件包,其中包括AbstractComboBox - 其描述表明它可以做到这一点。

However, it's a paid-for package and I haven't tried it... If anyone has used this, could they comment on the experience? 然而,这是一个付费的套餐,我没有尝试过......如果有人使用过它,他们可以评论一下经验吗?

You just need to extend the BasicComboBoxUI and then override required methods like 您只需要扩展BasicComboBoxUI,然后覆盖所需的方法,如

public static ComponentUI createUI( JComponent c) 

and

protected ComboPopup createPopup()

Creating a custom ComboPopup would require you to put some effort where you can't use the BasicComboPopUp because it extends JPopUpMenu 创建自定义ComboPopup需要您在不能使用BasicComboPopUp的地方付出一些努力,因为它扩展了JPopUpMenu

public class BasicComboPopup extends JPopupMenu implements ComboPopup

So in your case you may want to extend JTree and implement ComboPopup. 因此,在您的情况下,您可能希望扩展JTree并实现ComboPopup。

I'm doubt about "The problem in changing that is that it would need to be re-implemented for each look and feel" part. 我怀疑“改变的问题在于它需要为每个外观和感觉重新实现”。 I don't think that there will be a problem of re-implementation. 我不认为会有重新实施的问题。

The BasicComboPopup looks differently in different look and feels because it is a JPopupMenu which in turn will have UI delegates. BasicComboPopup在不同的外观和外观上看起来不同,因为它是JPopupMenu,而后者又具有UI委托。 So if you simply extend a JTree you should not be having problems with different look and feels. 因此,如果您只是扩展一个JTree,您应该不会遇到不同的外观和感觉问题。

The answer to use a button that pops up a JPanel with a JTree is correct. 使用弹出带有JTree的JPanel的按钮的答案是正确的。 In response to Carcassi's comment, you can use a custom TableCellRenderer to change it so that it does not look like the traditional button. 回应Carcassi的评论,您可以使用自定义TableCellRenderer进行更改,使其看起来不像传统按钮。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM