【问题标题】:What is the Swing-equivalent to HTML <optgroup>什么是与 HTML <optgroup> 等效的 Swing
【发布时间】:2015-02-22 11:43:04
【问题描述】:

我希望我的 JComboBox 将多个选项组合在一起,类似于 HTML optgroup:

<select>  
 <optgroup label="A">  
  <option/>
  <option/>  
 </optgroup>
</select>  

我在 Swing 中找不到任何解决方案。为 Combobox 操作 UI-Renderer 似乎是个坏主意,因为它依赖于操作系统和 L&F(它们是私有的,因此无法扩展)。

【问题讨论】:

    标签: java swing combobox optgroup


    【解决方案1】:

    考虑以下实现作为如何应用自定义样式和创建不可选择项的基本指南:

    public class ExtendedComboBox extends JComboBox {
    
        public ExtendedComboBox() {
            setModel(new ExtendedComboBoxModel());
            setRenderer(new ExtendedListCellRenderer());
        }
    
        public void addDelimiter(String text) {
            this.addItem(new Delimiter(text));
        }
    
        private static class ExtendedComboBoxModel extends DefaultComboBoxModel {
            @Override
            public void setSelectedItem(Object anObject) {
                if (!(anObject instanceof Delimiter)) {
                    super.setSelectedItem(anObject);
                } else {
                    int index = getIndexOf(anObject);
                    if (index < getSize()) {
                        setSelectedItem(getElementAt(index+1));
                    }
                }
            }
    
        }
    
        private static class ExtendedListCellRenderer 
                        extends DefaultListCellRenderer {
    
            @Override
            public Component getListCellRendererComponent(JList list, Object value,
                            int index, boolean isSelected, boolean cellHasFocus) {
                if (!(value instanceof Delimiter)) {
                    return super.getListCellRendererComponent(list, value, index,
                            isSelected, cellHasFocus);
                } else {
                    JLabel label = new JLabel(value.toString());
                    Font f = label.getFont();
                    label.setFont(f.deriveFont(f.getStyle() 
                               | Font.BOLD | Font.ITALIC));
                    return label;
                }
            }
        }
    
        private static class Delimiter {
            private String text;
    
            private Delimiter(String text) {
                this.text = text;
            }
    
            @Override
            public String toString() {
                return text.toString();
            }
        }
    }
    

    【讨论】:

    • 是的,这个例子几乎完全符合我的要求,我得到了它的工作。非常感谢。
    • 这也让我走上了正轨,但我想了解如何覆盖 DefaultListSelectionModel 而不是 DefaultComboBoxModel,以防止选择分隔符。我已经使用 GlazedLists 创建了一个基于 EventList 的 EventList 和一个 SeparatorList,并且我正在使用 DefaultEventListModel 作为模型(传入我的 SeparatorList)和一个自定义 CellRenderer 创建一个 JList。一切都显示得很好,现在我只需要阻止选择分隔单元格... DefaultListSelectionModel 与 DefaultComboBoxModel 完全不同...
    【解决方案2】:

    您可以在自定义渲染器中执行此操作,如 How to Use Combo Boxes: Providing a Custom Renderer 中所述。

    【讨论】:

    【解决方案3】:

    我不相信有一种简单的方法可以做到这一点,但有一种方法可以做到。

    我将实现一个数据模型类来指示您在上面描述的分组。将这些数据模型的实例放在您的 javax.swing.ComboBoxModel 实现实例中。

    然后,您可以实现 javax.swing.ListCellRenderer 以根据需要格式化输出,并为文本数据使用缩进。您可能只想扩展 javax.swing.DefaultListCellRenderer 或可能从 Java 源代码中大量借用它的实现。

    至于 L&F,您应该能够通过使用上述方法保持在正常的指导范围内,并且您不必为弄清楚如何实施它而苦苦挣扎。查看默认的 Swing 组件,它们将为如何处理 L&F 提供很多见解。

    此外,我认为有一些机制(您必须原谅我,我已经完成了完整的 Swing 开发已经有好几年了)可以让您确定一个项目是否可选。

    【讨论】:

      【解决方案4】:

      我今天自己也想要这个,我花了一天的时间想办法把它拼凑起来,用 JList 而不是建议的 JComboBox 实现一个类似的模型。我终于想出了一个使用 GlazedLists EventList 和 SeparatorList 以及相应的 DefaultEventListModel 的解决方案。我覆盖了 CellRenderer 和 DefaultListSelectionModel。最后我发布了我自己对这个问题的回答:How to prevent selection of SeparatorList.Separator in a JList?

      这是我的最终工作代码:

      public class MyFrame extends javax.swing.JFrame {
          private final EventList<BibleVersion> bibleVersions;
          private final SeparatorList<BibleVersion> versionsByLang;
          private boolean[] enabledFlags;
      
          public MyFrame(){
              bibleVersions = new BasicEventList<>();
              bibleVersions.add(new BibleVersion("CEI2008", "Testo della Conferenza Episcopale Italiana", "2008", "Italian"));
              bibleVersions.add(new BibleVersion("LUZZI", "Diodati Nuova Riveduta - Luzzi", "1927", "Italian"));
              bibleVersions.add(new BibleVersion("NVBSE", "Nova Vulgata - Bibliorum Sacrorum Editio", "1979", "Latin"));
              bibleVersions.add(new BibleVersion("NABRE", "New American Bible - Revised Edition", "2011", "English"));
              bibleVersions.add(new BibleVersion("KJV", "King James Version", "1611", "English"));
              versionsByLang = new SeparatorList<>(bibleVersions, new VersionComparator(),1, 1000);
              int listLength = versionsByLang.size();
              enabledFlags = new boolean[listLength];
      
              ListIterator itr = versionsByLang.listIterator();
              while(itr.hasNext()){
                  enabledFlags[itr.nextIndex()] = !(itr.next().getClass().getSimpleName().equals("GroupSeparator"));
              }
              jList = new javax.swing.JList();
              jList.setModel(new DefaultEventListModel<>(versionsByLang));
              jList.setCellRenderer(new VersionCellRenderer());
              jList.setSelectionModel(new DisabledItemSelectionModel());
              ListSelectionModel listSelectionModel = jList.getSelectionModel();
              listSelectionModel.addListSelectionListener(new SharedListSelectionHandler());
      
          }
      
          public static class BibleVersion {
              private String abbrev;
              private String fullname;
              private String year;
              private String lang;
      
              public BibleVersion(String abbrev, String fullname, String year, String lang) {
                  this.abbrev = abbrev;
                  this.fullname = fullname;
                  this.year = year;
                  this.lang = lang;
              }        
      
              public String getAbbrev() {
                  return abbrev;
              }
      
              public void setAbbrev(String abbrev) {
                  this.abbrev = abbrev;
              }
      
              public String getFullname() {
                  return fullname;
              }
      
              public void setFullname(String fullname) {
                  this.fullname = fullname;
              }
      
              public String getYear() {
                  return year;
              }
      
              public void setYear(String year) {
                  this.year = year;
              }
      
              public String getLang() {
                  return lang;
              }
      
              public void setLang(String lang) {
                  this.lang = lang;
              }
      
              @Override
              public String toString() {
                  return this.getAbbrev() + " — " + this.getFullname() + " (" + this.getYear() + ")"; //To change body of generated methods, choose Tools | Templates.
              }                
      
          }
      
          private static class VersionComparator implements Comparator<BibleVersion> {
      
              @Override
              public int compare(BibleVersion o1, BibleVersion o2) {
                  return o1.getLang().compareTo(o2.getLang());
              }            
      
          }
      
          private static class VersionCellRenderer extends DefaultListCellRenderer{
      
              @Override
              public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                  JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
      
                  if (value instanceof SeparatorList.Separator) {
                      SeparatorList.Separator separator = (SeparatorList.Separator) value;
                      BibleVersion bibleversion = (BibleVersion)separator.getGroup().get(0);
                      String lbl = "-- " + bibleversion.getLang() + " --";
                      label.setText(lbl);
                      label.setFont(label.getFont().deriveFont(Font.BOLD));
                      label.setBackground(Color.decode("#004400"));
                      label.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
                      label.setEnabled(false);
                  } else {
                      label.setFont(label.getFont().deriveFont(Font.PLAIN));
                      label.setBorder(BorderFactory.createEmptyBorder(0,15,0,0));
                  }
      
                  return label;
              }
          }
      
      private class DisabledItemSelectionModel extends DefaultListSelectionModel {
      
          private static final long serialVersionUID = 1L;
      
          @Override
          public void setSelectionInterval(int index0, int index1) {
              if(index0 < index1){
                  for (int i = index0; i <= index1; i++){
                      if(enabledFlags[i]){
                          super.addSelectionInterval(i, i);
                      }
                  }
              }
              else if(index1 < index0){
                  for (int i = index1; i <= index0; i++){
                      if(enabledFlags[i]){
                          super.addSelectionInterval(i, i);
                      }
                  }
              }
              else if(index0 == index1){
                  if(enabledFlags[index0]){ super.setSelectionInterval(index0,index0); }
              }
          }
      
          @Override
          public void addSelectionInterval(int index0, int index1) {
              if(index0 < index1){
                  for (int i = index0; i <= index1; i++){
                      if(enabledFlags[i]){
                          super.addSelectionInterval(i, i);
                      }
                  }
              }
              else if(index1 < index0){
                  for (int i = index1; i <= index0; i++){
                      if(enabledFlags[i]){
                          super.addSelectionInterval(i, i);
                      }
                  }
              }
              else if(index0 == index1){
                  if(enabledFlags[index0]){ super.addSelectionInterval(index0,index0); }
              }
          }        
      
      }
      
      private class SharedListSelectionHandler implements ListSelectionListener {
          @Override
          public void valueChanged(ListSelectionEvent e) {
              ListSelectionModel lsm = (ListSelectionModel)e.getSource();
              StringBuilder output = new StringBuilder();
              int firstIndex = e.getFirstIndex();
              int lastIndex = e.getLastIndex();
              boolean isAdjusting = e.getValueIsAdjusting();
              output.append("Event for indexes ");
              output.append(firstIndex);
              output.append(" - ");
              output.append(lastIndex);
              output.append("; isAdjusting is ");
              output.append(isAdjusting);
              output.append("; selected indexes:");
      
              if (lsm.isSelectionEmpty()) {
                  output.append(" <none>");
              } else {
                  // Find out which indexes are selected.
                  int minIndex = lsm.getMinSelectionIndex();
                  int maxIndex = lsm.getMaxSelectionIndex();
                  for (int i = minIndex; i <= maxIndex; i++) {
                      if (lsm.isSelectedIndex(i)) {
                          output.append(" ");
                          output.append(i);
                      }
                  }
              }
              output.append(System.getProperty("line.separator"));
              System.out.println(output.toString());
          }
      }
      
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-26
        • 2011-03-11
        • 2010-11-27
        • 1970-01-01
        • 2016-08-06
        • 2018-01-16
        • 2011-07-02
        • 2017-05-26
        相关资源
        最近更新 更多