我希望我的JComboBox將多個選項一起,類似於HTML optgroup
:什麼是Swing的等同於HTML <optgroup>
<select>
<optgroup label="A">
<option/>
<option/>
</optgroup>
</select>
我找不到在Swing這方面的任何解決方案。操縱Combobox的UI-Renderer似乎不是一個好主意,因爲它依賴於F(並且它們是私有的,所以不能擴展)。
我希望我的JComboBox將多個選項一起,類似於HTML optgroup
:什麼是Swing的等同於HTML <optgroup>
<select>
<optgroup label="A">
<option/>
<option/>
</optgroup>
</select>
我找不到在Swing這方面的任何解決方案。操縱Combobox的UI-Renderer似乎不是一個好主意,因爲它依賴於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();
}
}
}
我不相信有這樣一個簡單的方法,但有一種方法可以做到這一點。
我會實現一個數據模型類,指出您在上面描述的分組。將這些數據模型的實例放入您的javax.swing.ComboBoxModel實現實例中。
然後,您可以實現javax.swing.ListCellRenderer以根據您的喜好使用文本數據的縮進來格式化輸出。您可能只想擴展javax.swing.DefaultListCellRenderer,或者可能需要從Java源代碼中批量使用批量實現。
至於L & F您應該能夠通過使用上述方法保持在正常的指導範圍內,您將不必爲解決如何實施它而戰鬥。看看默認的Swing組件,他們將提供大量的洞察力來處理如何處理L & F.
此外,我認爲有機制(你將不得不原諒我,因爲我已經過去了一年完成Swing開發),讓您確定項目是否可選。
+1建議自定義模型。 – trashgod
您可以在自定義渲染器中執行此操作,如How to Use Combo Boxes: Providing a Custom Renderer中所述。
好的建議。我忘了Java教程(http://download.oracle.com/javase/tutorial/) –
是的,該教程幫助了我很多,謝謝。 –
我今天想這一點我自己,我已經花了一天想出來的東西拼湊共同實現一個與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());
}
}
}
是的,這個例子幾乎可以說是我所要求的,我知道它的工作原理。非常感謝。 –
這讓我在正確的軌道上,但我想了解如何重寫DefaultListSelectionModel而不是DefaultComboBoxModel,以防止選擇分隔符。我已經使用GlazedLists基於EventList創建EventList和SeparatorList,並且使用DefaultEventListModel作爲模型(傳入我的SeparatorList)和自定義CellRenderer來創建JList。所有的顯示都很好,現在我只需要防止選擇分隔單元... DefaultListSelectionModel與DefaultComboBoxModel完全不同... – JohnRDOrazio