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

为君一笑 提交于 2020-01-24 05:28:06

问题


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...

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).

What's the easiest way to do that?


回答1:


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).




回答2:


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.

So then I tried the button approach... and thought I would share the code with the SO community:

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:


You just need to extend the BasicComboBoxUI and then override required methods like

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

public class BasicComboPopup extends JPopupMenu implements ComboPopup

So in your case you may want to extend JTree and implement 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.




回答4:


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.




回答5:


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.

However, it's a paid-for package and I haven't tried it... If anyone has used this, could they comment on the experience?



来源:https://stackoverflow.com/questions/1791179/how-do-i-customize-a-jcombobox-so-that-the-pop-up-is-a-jtree-instead-of-a-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!