如何在Java中向JComboBox添加分隔符?

如何在Java中向JComboBox添加分隔符?,java,swing,jcombobox,jseparator,Java,Swing,Jcombobox,Jseparator,我有一个JComboBox,希望在元素列表中有一个分隔符。如何在Java中实现这一点 在一个示例场景中,当为字体系列选择创建一个组合框时,这将派上用场;类似于Word和Excel中的字体族选择控件。在本例中,我想在顶部显示最常用的字体,然后是分隔符,最后是按字母顺序显示分隔符下面的所有字体系列 有人能帮我做这件事吗?这在Java中是不可能的吗?您可以使用自定义的ListCellRenderer,它将以不同的方式绘制分隔符项。请参阅和一个小教程。有一个非常简短的教程,其中有一个示例,演示如何在ja

我有一个JComboBox,希望在元素列表中有一个分隔符。如何在Java中实现这一点

在一个示例场景中,当为字体系列选择创建一个组合框时,这将派上用场;类似于Word和Excel中的字体族选择控件。在本例中,我想在顶部显示最常用的字体,然后是分隔符,最后是按字母顺序显示分隔符下面的所有字体系列


有人能帮我做这件事吗?这在Java中是不可能的吗?

您可以使用自定义的
ListCellRenderer
,它将以不同的方式绘制分隔符项。请参阅和一个小教程。

有一个非常简短的教程,其中有一个示例,演示如何在java2s上使用自定义ListCellRenderer


基本上,它包括在列表模型中插入一个已知的占位符,当您在ListCellRenderer中检测到占位符时,您将返回一个“new JSepator(JSepator.HORIZONTAL)”的实例。

在我编写和测试下面的代码时,您可能得到了很多更好的答案……
我不介意,因为我喜欢这个实验/学习(秋千的正面还是有点绿)

[编辑]三年后,我的环保意识有所下降,我考虑到了Bobndew的合理评论。我对刚刚工作的键导航没有问题(可能是JVM版本问题?)。不过,我改进了渲染器以显示高光。我使用了更好的演示代码。被接受的答案可能更好(更标准),如果你想要自定义分隔符,我的答案可能更灵活

基本思想是对组合框的项目使用渲染器。对于大多数项目,它是一个带有项目文本的简单JLabel。对于最近/最常用的项目,我用自定义边框在其底部绘制一条线来装饰JLabel

import java.awt.*;
import javax.swing.*;


@SuppressWarnings("serial")
public class TwoPartsComboBox extends JComboBox
{
  private int m_lastFirstPartIndex;

  public TwoPartsComboBox(String[] itemsFirstPart, String[] itemsSecondPart)
  {
    super(itemsFirstPart);
    m_lastFirstPartIndex = itemsFirstPart.length - 1;
    for (int i = 0; i < itemsSecondPart.length; i++)
    {
      insertItemAt(itemsSecondPart[i], i);
    }

    setRenderer(new JLRenderer());
  }

  protected class JLRenderer extends JLabel implements ListCellRenderer
  {
    private JLabel m_lastFirstPart;

    public JLRenderer()
    {
      m_lastFirstPart = new JLabel();
      m_lastFirstPart.setBorder(new BottomLineBorder());
//      m_lastFirstPart.setBorder(new BottomLineBorder(10, Color.BLUE));
    }

    @Override
    public Component getListCellRendererComponent(
        JList list,
        Object value,
        int index,
        boolean isSelected,
        boolean cellHasFocus)
    {
      if (value == null)
      {
        value = "Select an option";
      }
      JLabel label = this;
      if (index == m_lastFirstPartIndex)
      {
        label = m_lastFirstPart;
      }
      label.setText(value.toString());
      label.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
      label.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
      label.setOpaque(true);

      return label;
    }
  }
}
测试等级:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


@SuppressWarnings("serial")
public class TwoPartsComboBoxDemo extends JFrame
{
  private TwoPartsComboBox m_combo;

  public TwoPartsComboBoxDemo()
  {
    Container cont = getContentPane();
    cont.setLayout(new FlowLayout());

    cont.add(new JLabel("Data: ")) ;

    String[] itemsRecent = new String[] { "ichi", "ni", "san" };
    String[] itemsOther = new String[] { "one", "two", "three" };
    m_combo = new TwoPartsComboBox(itemsRecent, itemsOther);

    m_combo.setSelectedIndex(-1);
    cont.add(m_combo);
    m_combo.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent ae)
      {
        String si = (String) m_combo.getSelectedItem();
        System.out.println(si == null ? "No item selected" : si.toString());
      }
    });

    // Reference, to check we have similar behavior to standard combo
    JComboBox combo = new JComboBox(itemsRecent);
    cont.add(combo);
  }

  /**
   * Start the demo.
   *
   * @param args   the command line arguments
   */
  public static void main(String[] args)
  {
    // turn bold fonts off in metal
    UIManager.put("swing.boldMetal", Boolean.FALSE);

    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        JFrame demoFrame = new TwoPartsComboBoxDemo();
        demoFrame.setTitle("Test GUI");
        demoFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        demoFrame.setSize(400, 100);
        demoFrame.setVisible(true);
      }
    });
  }
}

在这里,变量命名并不是最糟糕的事情:您正在破坏整个组合框项选择:选择不再被绘制,并且第一个字母键跳转被破坏。您应该在尽可能小的范围内(在
publicttestgui()
中)定义
m_组合
m_呈现程序
)。并且不应该对渲染器和“TestGui”类(应该是单独的主类,而不是“JFrame”子类)使用gloobal
m_lastRecentIndex
)。但是我喜欢牙套的样式@波德鲁:嘿!正如我写的,我当时是个新手(已经3年了!)。在你们没有指出的错误中,我可能使用了我发现的一些Swing测试模板,更糟糕的是,我没有使用SwingUtilities.invokeLater!我目前的代码至少使用了它(但它仍然是一个JFrame子类…)。而且m_lastRecentIndex更本地化。。。但是您的大多数批评都是关于一个快速生成的测试类,它不是真正的生产代码。今天,我更加关注这些代码,因为新手可以从中获得灵感…:-)另外,关于突出显示悬停元素和选定内容,您是正确的。TODONote:我编辑了上面的代码以获得更现代/正确的版本。我的方法的一个优点是,它比JSepator更灵活(至少在外观上),而且不占用任何时间。示例
BlockComboBoxExample
打破了光标键和第一个字母键的导航。桑托什·库马尔的似乎效果更好。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


@SuppressWarnings("serial")
public class TwoPartsComboBoxDemo extends JFrame
{
  private TwoPartsComboBox m_combo;

  public TwoPartsComboBoxDemo()
  {
    Container cont = getContentPane();
    cont.setLayout(new FlowLayout());

    cont.add(new JLabel("Data: ")) ;

    String[] itemsRecent = new String[] { "ichi", "ni", "san" };
    String[] itemsOther = new String[] { "one", "two", "three" };
    m_combo = new TwoPartsComboBox(itemsRecent, itemsOther);

    m_combo.setSelectedIndex(-1);
    cont.add(m_combo);
    m_combo.addActionListener(new ActionListener()
    {
      public void actionPerformed(ActionEvent ae)
      {
        String si = (String) m_combo.getSelectedItem();
        System.out.println(si == null ? "No item selected" : si.toString());
      }
    });

    // Reference, to check we have similar behavior to standard combo
    JComboBox combo = new JComboBox(itemsRecent);
    cont.add(combo);
  }

  /**
   * Start the demo.
   *
   * @param args   the command line arguments
   */
  public static void main(String[] args)
  {
    // turn bold fonts off in metal
    UIManager.put("swing.boldMetal", Boolean.FALSE);

    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        JFrame demoFrame = new TwoPartsComboBoxDemo();
        demoFrame.setTitle("Test GUI");
        demoFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        demoFrame.setSize(400, 100);
        demoFrame.setVisible(true);
      }
    });
  }
}