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

发布于 2024-07-05 11:06:56 字数 239 浏览 8 评论 0原文

我有一个 JComboBox 并且希望在元素列表中添加分隔符。 我如何在 Java 中执行此操作?

一个可以派上用场的示例场景是在制作用于字体系列选择的组合框时; 类似于 Word 和 Excel 中的字体系列选择控件。 在这种情况下,我想在顶部显示最常用的字体,然后是分隔符,最后按字母顺序显示分隔符下方的所有字体系列。

任何人都可以帮助我如何做到这一点,或者这在 Java 中是不可能的吗?

I have a JComboBox and would like to have a separator in the list of elements. How do I do this in Java?

A sample scenario where this would come in handy is when making a combobox for font-family-selection; similar to the font-family-selection-control in Word and Excel. In this case I would like to show the most-used-fonts at the top, then a separator and finally all font-families below the separator in alphabetical order.

Can anyone help me with how to do this or is this not possible in Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

凉薄对峙 2024-07-12 11:06:56

有一个非常简短的教程,其中包含一个示例,展示了如何在 java2s 上使用自定义 ListCellRenderer
http://www.java2s.com/Code/Java/Swing-Components /BlockComboBoxExample.htm

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

There is a pretty short tutorial with an example that shows how to use a custom ListCellRenderer on java2s
http://www.java2s.com/Code/Java/Swing-Components/BlockComboBoxExample.htm

Basically it involves inserting a known placeholder in your list model and when you detect the placeholder in the ListCellRenderer you return an instance of 'new JSeparator(JSeparator.HORIZONTAL)'

千纸鹤带着心事 2024-07-12 11:06:56

当我编写并测试下面的代码时,您可能会得到很多更好的答案......
我不介意,因为我喜欢实验/学习(Swing 前端仍然有点绿)。

[编辑] 三年后,我不再那么绿了,我考虑了 bobndrew 的有效言论。 我对正常运行的按键导航没有任何问题(也许是 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 javax.swing.border.AbstractBorder;

/**
 * Draws a line at the bottom only.
 * Useful for making a separator in combo box, for example.
 */
@SuppressWarnings("serial")
class BottomLineBorder extends AbstractBorder
{
  private int m_thickness;
  private Color m_color;

  BottomLineBorder()
  {
    this(1, Color.BLACK);
  }

  BottomLineBorder(Color color)
  {
    this(1, color);
  }

  BottomLineBorder(int thickness, Color color)
  {
    m_thickness = thickness;
    m_color = color;
  }

  @Override
  public void paintBorder(Component c, Graphics g,
      int x, int y, int width, int height)
  {
    Graphics copy = g.create();
    if (copy != null)
    {
      try
      {
        copy.translate(x, y);
        copy.setColor(m_color);
        copy.fillRect(0, height - m_thickness, width - 1, height - 1);
      }
      finally
      {
        copy.dispose();
      }
    }
  }

  @Override
  public boolean isBorderOpaque()
  {
    return true;
  }
  @Override
  public Insets getBorderInsets(Component c)
  {
    return new Insets(0, 0, m_thickness, 0);
  }
  @Override
  public Insets getBorderInsets(Component c, Insets i)
  {
    i.left = i.top = i.right = 0;
    i.bottom = m_thickness;
    return i;
  }
}

测试类:

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);
      }
    });
  }
}

By the time I wrote and tested the code below, you probably got lot of better answers...
I don't mind as I enjoyed the experiment/learning (still a bit green on the Swing front).

[EDIT] Three years later, I am a bit less green, and I took in account the valid remarks of bobndrew. I have no problem with the key navigation that just works (perhaps it was a JVM version issue?). I improved the renderer to show highlight, though. And I use a better demo code. The accepted answer is probably better (more standard), mine is probably more flexible if you want a custom separator...

The base idea is to use a renderer for the items of the combo box. For most items, it is a simple JLabel with the text of the item. For the last recent/most used item, I decorate the JLabel with a custom border drawing a line on its bottom.

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;
    }
  }
}

Separator class, can be thick, with custom color, etc.

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

/**
 * Draws a line at the bottom only.
 * Useful for making a separator in combo box, for example.
 */
@SuppressWarnings("serial")
class BottomLineBorder extends AbstractBorder
{
  private int m_thickness;
  private Color m_color;

  BottomLineBorder()
  {
    this(1, Color.BLACK);
  }

  BottomLineBorder(Color color)
  {
    this(1, color);
  }

  BottomLineBorder(int thickness, Color color)
  {
    m_thickness = thickness;
    m_color = color;
  }

  @Override
  public void paintBorder(Component c, Graphics g,
      int x, int y, int width, int height)
  {
    Graphics copy = g.create();
    if (copy != null)
    {
      try
      {
        copy.translate(x, y);
        copy.setColor(m_color);
        copy.fillRect(0, height - m_thickness, width - 1, height - 1);
      }
      finally
      {
        copy.dispose();
      }
    }
  }

  @Override
  public boolean isBorderOpaque()
  {
    return true;
  }
  @Override
  public Insets getBorderInsets(Component c)
  {
    return new Insets(0, 0, m_thickness, 0);
  }
  @Override
  public Insets getBorderInsets(Component c, Insets i)
  {
    i.left = i.top = i.right = 0;
    i.bottom = m_thickness;
    return i;
  }
}

Test class:

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);
      }
    });
  }
}
梦罢 2024-07-12 11:06:56

尝试添加此渲染器。 只需提供您希望分隔符位于上方的索引值列表即可。

 private class SeperatorComboRenderer extends DefaultListCellRenderer
 {
      private final float SEPARATOR_THICKNESS = 1.0f;
      private final float SPACE_TOP = 2.0f;
      private final float SPACE_BOTTOM = 2.0f;
      private final Color SEPARATOR_COLOR = Color.DARK_GRAY;
    
      private final List<Integer> marks;
      private boolean mark;
      private boolean top;
    
      public SeperatorComboRenderer(List<Integer> marks)
      {
           this.marks = marks;
      }
    
      @Override
      public Component getListCellRendererComponent(JList list, Object object, int index, boolean isSelected, boolean hasFocus)
      {
           super.getListCellRendererComponent(list, object, index, isSelected, hasFocus);

           top = false;
           mark = false;
           marks.forEach((idx) ->
           {
               if(index - 1 == idx)
                    top = true;
               if(index == idx)
                    mark = true;
           });
           return this;
      }
    
      @Override
      protected void paintComponent(Graphics g)
      {
           if(mark)
                g.translate(0, (int)(SEPARATOR_THICKNESS + SPACE_BOTTOM));
           Graphics2D g2 = (Graphics2D)g;
           super.paintComponent(g);
           if(mark)
           {
                g2.setColor(SEPARATOR_COLOR);
                g2.setStroke(new BasicStroke(SEPARATOR_THICKNESS));
                g2.drawLine(0, 0, getWidth(), 0);
           }
      }
    
      @Override
      public Dimension getPreferredSize()
      {
           Dimension pf = super.getPreferredSize();
           double height = pf.getHeight();
           if(top) height += SPACE_TOP;
           else if(mark) height += SEPARATOR_THICKNESS + SPACE_BOTTOM;
           return new Dimension((int)pf.getWidth(), (int)height);
      }
  }

Try adding this renderer. Just supply a list of index values that you want the separator to be above.

 private class SeperatorComboRenderer extends DefaultListCellRenderer
 {
      private final float SEPARATOR_THICKNESS = 1.0f;
      private final float SPACE_TOP = 2.0f;
      private final float SPACE_BOTTOM = 2.0f;
      private final Color SEPARATOR_COLOR = Color.DARK_GRAY;
    
      private final List<Integer> marks;
      private boolean mark;
      private boolean top;
    
      public SeperatorComboRenderer(List<Integer> marks)
      {
           this.marks = marks;
      }
    
      @Override
      public Component getListCellRendererComponent(JList list, Object object, int index, boolean isSelected, boolean hasFocus)
      {
           super.getListCellRendererComponent(list, object, index, isSelected, hasFocus);

           top = false;
           mark = false;
           marks.forEach((idx) ->
           {
               if(index - 1 == idx)
                    top = true;
               if(index == idx)
                    mark = true;
           });
           return this;
      }
    
      @Override
      protected void paintComponent(Graphics g)
      {
           if(mark)
                g.translate(0, (int)(SEPARATOR_THICKNESS + SPACE_BOTTOM));
           Graphics2D g2 = (Graphics2D)g;
           super.paintComponent(g);
           if(mark)
           {
                g2.setColor(SEPARATOR_COLOR);
                g2.setStroke(new BasicStroke(SEPARATOR_THICKNESS));
                g2.drawLine(0, 0, getWidth(), 0);
           }
      }
    
      @Override
      public Dimension getPreferredSize()
      {
           Dimension pf = super.getPreferredSize();
           double height = pf.getHeight();
           if(top) height += SPACE_TOP;
           else if(mark) height += SEPARATOR_THICKNESS + SPACE_BOTTOM;
           return new Dimension((int)pf.getWidth(), (int)height);
      }
  }
眼眸里的那抹悲凉 2024-07-12 11:06:56

您可以使用自定义的 ListCellRenderer 来以不同的方式绘制分隔符项目。 请参阅 文档和一个小教程< /a>.

You can use a custom ListCellRenderer which would draw the separator items differently. See docs and a small tutorial.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文