如何自定义JComboBox,使弹出式是JTree(而不是列表)?

时间:2022-11-22 12:38:32

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. Having a look at how the JComboBox is implement, the pop-up is really created by the UI delegate. 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...

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

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?

最简单的方法是什么?

5 个解决方案

#1


2  

JComboBox itself can't do what you want. 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. Then the JPanel could have whatever you want inside it (JTree, etcetera).

JComboBox本身不能做您想做的事情。如果您完全坚持让它充当JComboBox的概念,您可以在单击时让JButton弹出JPanel。然后JPanel可以包含任何您想要的内容(JTree等)。

#2


1  

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). If anyone has a good example of doing this, I'd be interested to see it.

起初,我试图按照Varun的建议来实现一些东西,但事实证明它有点混乱,当我开始使用ComponentUI对象时,我有点紧张(我宁愿把这类东西留给L&F)。如果有人有这样做的好例子,我很想看看。

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!

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

#3


0  

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

创建自定义梳状图将需要您在无法使用basic梳状图的地方投入一些精力,因为它扩展了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. So if you simply extend a JTree you should not be having problems with different look and feels.

basiccombopup在不同的外观和感觉上看起来是不同的,因为它是一个JPopupMenu,它反过来会有UI委托。因此,如果您只是扩展一个JTree,那么您就不会遇到外观和感觉不同的问题。

#4


0  

The answer to use a button that pops up a JPanel with a JTree is correct. 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.

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

#5


0  

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.

进一步的web研究显示,Jidesoft自称是“专业的Java和Swing组件供应商”,他生产了一个名为JIDE grid的包,其中包括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?

不过,这是付费套餐,我还没试过……如果有人用过这个,他们能评论一下这个经历吗?

#1


2  

JComboBox itself can't do what you want. 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. Then the JPanel could have whatever you want inside it (JTree, etcetera).

JComboBox本身不能做您想做的事情。如果您完全坚持让它充当JComboBox的概念,您可以在单击时让JButton弹出JPanel。然后JPanel可以包含任何您想要的内容(JTree等)。

#2


1  

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). If anyone has a good example of doing this, I'd be interested to see it.

起初,我试图按照Varun的建议来实现一些东西,但事实证明它有点混乱,当我开始使用ComponentUI对象时,我有点紧张(我宁愿把这类东西留给L&F)。如果有人有这样做的好例子,我很想看看。

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!

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

#3


0  

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

创建自定义梳状图将需要您在无法使用basic梳状图的地方投入一些精力,因为它扩展了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. So if you simply extend a JTree you should not be having problems with different look and feels.

basiccombopup在不同的外观和感觉上看起来是不同的,因为它是一个JPopupMenu,它反过来会有UI委托。因此,如果您只是扩展一个JTree,那么您就不会遇到外观和感觉不同的问题。

#4


0  

The answer to use a button that pops up a JPanel with a JTree is correct. 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.

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

#5


0  

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.

进一步的web研究显示,Jidesoft自称是“专业的Java和Swing组件供应商”,他生产了一个名为JIDE grid的包,其中包括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?

不过,这是付费套餐,我还没试过……如果有人用过这个,他们能评论一下这个经历吗?