什么是Swing – 相当于HTML

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

       

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

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

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

您可以在自定义渲染器中执行此操作,如如何使用combobox:提供自定义渲染器中所述

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

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

然后,您可以使用javax.swing.ListCellRenderer实现格式化输出,并使用文本数据的缩进。 您可能只想扩展javax.swing.DefaultListCellRenderer或者可能从Java源中借用其实现批发。

至于L&F,您应该能够通过使用上述方法保持在正常的指导范围内,并且您不必为解决如何实施它而斗争。 看看默认的Swing组件,他们将提供有关如何处理L&F的大量见解。

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

我今天自己也想要这个,而且我花了一天时间把它拼凑起来用JList而不是建议的JComboBox来实现类似的模型。 我终于想出了一个使用GlazedLists EventList和SeparatorList以及相应的DefaultEventListModel的解决方案。 我重写了CellRenderer和DefaultListSelectionModel。 最后我在自己的问题上发布了自己的答案: 如何防止在JList中选择SeparatorList.Separator?

这是我最后的工作代码:

 public class MyFrame extends javax.swing.JFrame { private final EventList bibleVersions; private final SeparatorList 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 { @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(" "); } 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()); } } }