如何防止在 JList 中选择 SeparatorList.Separator?
How to prevent selection of SeparatorList.Separator in a JList?
我使用 GrazedLists 创建了一个 JList,特别是一个 EventList,然后我将其传递到一个带有自定义比较器的 SeparatorList,该比较器对我的 EventList 元素进行排序。
我使用 DefaultEventListModel 作为 JList 模型,传入我的 SeparatorList。
我正在使用自定义 CellRenderer 来装饰 SeparatorList.Separator 单元格。一切都很好地显示,我看到一个格式很好的列表,按照我喜欢的方式分组,类似于 HTML SELECT 元素中的 optgroups。
现在我想阻止选择分隔符单元格。
我看到了如何覆盖 DefaultComboBoxModel 的示例。但是我不知道如何覆盖 DefaultListSelectionModel 或 DefaultEventListModel。
这是我目前所拥有的一些示例代码:
public class MyFrame extends javax.swing.JFrame {
private final EventList<BibleVersion> bibleVersions;
private final SeparatorList<BibleVersion> versionsByLang;
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);
jList = new javax.swing.JList();
jList.setModel(new DefaultEventListModel<>(versionsByLang));
jList.setCellRenderer(new VersionCellRenderer());
}
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.LIGHT_GRAY);
label.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
} else {
label.setFont(label.getFont().deriveFont(Font.PLAIN));
label.setBorder(BorderFactory.createEmptyBorder(0,15,0,0));
}
return label;
}
}
}
现在如何验证 DefaultEventListModel(或 ListSelectionModel)?我需要覆盖哪些,或者可能是 DefaultListSelectionModel? ListSelectionModel 似乎有许多需要重写的方法,用于处理 MULTIPLE_INTERVAL 选择(这是我的情况)。我不太确定从哪里开始...
通过反复试验,根据我在 找到的代码建议并以此为基础,我能够将一些现在运行良好的东西组合在一起。我不得不改变链接示例中的逻辑。基本上,我会在选定的索引之间走动,并一个一个地检查它们是否是 "enabled" 索引,如果是,我 "addSelectionInterval" 只是针对该索引。我对 setSelectionInterval 方法和 addSelectionInterval 方法都这样做。所以基本上你永远不会将选择作为一个块添加,总是通过循环遍历选择块并一个一个地检查它们是否启用选择。
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());
}
}
}
像这样写它工作得很好,禁用的单元格根本没有被 CTRL-click 选中,SHIFT-clicking 也很好地工作。单击一次可清除列表并仅选择已单击的元素(如果已启用选择)。
我使用 GrazedLists 创建了一个 JList,特别是一个 EventList,然后我将其传递到一个带有自定义比较器的 SeparatorList,该比较器对我的 EventList 元素进行排序。 我使用 DefaultEventListModel 作为 JList 模型,传入我的 SeparatorList。 我正在使用自定义 CellRenderer 来装饰 SeparatorList.Separator 单元格。一切都很好地显示,我看到一个格式很好的列表,按照我喜欢的方式分组,类似于 HTML SELECT 元素中的 optgroups。
现在我想阻止选择分隔符单元格。
我看到了如何覆盖 DefaultComboBoxModel 的示例。但是我不知道如何覆盖 DefaultListSelectionModel 或 DefaultEventListModel。
这是我目前所拥有的一些示例代码:
public class MyFrame extends javax.swing.JFrame {
private final EventList<BibleVersion> bibleVersions;
private final SeparatorList<BibleVersion> versionsByLang;
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);
jList = new javax.swing.JList();
jList.setModel(new DefaultEventListModel<>(versionsByLang));
jList.setCellRenderer(new VersionCellRenderer());
}
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.LIGHT_GRAY);
label.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
} else {
label.setFont(label.getFont().deriveFont(Font.PLAIN));
label.setBorder(BorderFactory.createEmptyBorder(0,15,0,0));
}
return label;
}
}
}
现在如何验证 DefaultEventListModel(或 ListSelectionModel)?我需要覆盖哪些,或者可能是 DefaultListSelectionModel? ListSelectionModel 似乎有许多需要重写的方法,用于处理 MULTIPLE_INTERVAL 选择(这是我的情况)。我不太确定从哪里开始...
通过反复试验,根据我在 找到的代码建议并以此为基础,我能够将一些现在运行良好的东西组合在一起。我不得不改变链接示例中的逻辑。基本上,我会在选定的索引之间走动,并一个一个地检查它们是否是 "enabled" 索引,如果是,我 "addSelectionInterval" 只是针对该索引。我对 setSelectionInterval 方法和 addSelectionInterval 方法都这样做。所以基本上你永远不会将选择作为一个块添加,总是通过循环遍历选择块并一个一个地检查它们是否启用选择。
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());
}
}
}
像这样写它工作得很好,禁用的单元格根本没有被 CTRL-click 选中,SHIFT-clicking 也很好地工作。单击一次可清除列表并仅选择已单击的元素(如果已启用选择)。