2011-03-08 18 views
8

我希望我的JComboBox將多個選項一起,類似於HTML optgroup什麼是Swing的等同於HTML <optgroup>

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

我找不到在Swing這方面的任何解決方案。操縱Combobox的UI-Renderer似乎不是一個好主意,因爲它依賴於F(並且它們是私有的,所以不能擴展)。

回答

12

考慮以下實現作爲基本指導如何應用自定義樣式,並創建非可選項目:

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(); 
     } 
    } 
} 
+0

是的,這個例子幾乎可以說是我所要求的,我知道它的工作原理。非常感謝。 –

+1

這讓我在正確的軌道上,但我想了解如何重寫DefaultListSelectionModel而不是DefaultComboBoxModel,以防止選擇分隔符。我已經使用GlazedLists基於EventList創建EventList和SeparatorList,並且使用DefaultEventListModel作爲模型(傳入我的SeparatorList)和自定義CellRenderer來創建JList。所有的顯示都很好,現在我只需要防止選擇分隔單元... DefaultListSelectionModel與DefaultComboBoxModel完全不同... – JohnRDOrazio

5

我不相信有這樣一個簡單的方法,但有一種方法可以做到這一點。

我會實現一個數據模型類,指出您在上面描述的分組。將這些數據模型的實例放入您的javax.swing.ComboBoxModel實現實例中。

然後,您可以實現javax.swing.ListCellRenderer以根據您的喜好使用文本數據的縮進來格式化輸出。您可能只想擴展javax.swing.DefaultListCellRenderer,或者可能需要從Java源代碼中批量使用批量實現。

至於L & F您應該能夠通過使用上述方法保持在正常的指導範圍內,您將不必爲解決如何實施它而戰鬥。看看默認的Swing組件,他們將提供大量的洞察力來處理如何處理L & F.

此外,我認爲有機制(你將不得不原諒我,因爲我已經過去了一年完成Swing開發),讓您確定項目是否可選。

+0

+1建議自定義模型。 – trashgod

2

我今天想這一點我自己,我已經花了一天想出來的東西拼湊共同實現一個與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()); 
    } 
} 


} 
相關問題