有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

添加新元素后,带有自定义CellRenderer的java Swing JList将消失

我正在使用自定义CellRenderer和上下文菜单来选择/取消选择、添加或删除列表中的元素,并使用复选框编写JList

一切正常,我可以选择项目,打开上下文菜单并通过它删除/添加元素。我的问题是,当我添加一个元素时,列表中的元素比开始时多,列表就会消失,我得到一个空白面板。例如,将新元素添加到列表中而不删除之前的元素时会发生这种情况

为了找出问题所在,我一直在尝试将代码降至最低,但我仍然不明白为什么它不能正常工作

我想知道的是,为什么我的列表会变为空白,以及如何防止它变为空白

当然,欢迎任何旁白或建议:)

谢谢


如果您想尝试一下,下面是完整的代码(左键单击以选择项目,右键单击以打开关联菜单):

复选框列表。爪哇

package misc;

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;

public class CheckBoxList extends JList {

    private int selection = -1;

    protected static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);

    public CheckBoxList(Model m) {
        this();
        this.setModel(m);
    }

    public CheckBoxList() {
        this.setCellRenderer(new CheckboxCellRenderer());
        this.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                int index = locationToIndex(e.getPoint());
                selection = index;
                CheckBoxList cbl = (CheckBoxList) e.getSource();
                cbl.setSelectedIndex(index);
                if(index != -1) {
                    if(e.getButton() == MouseEvent.BUTTON1) {
                        Data v = (Data) getModel().getElementAt(index);
                        v.setSelected(!v.isSelected());
                        JCheckBox checkbox = new JCheckBox(v.getS(), v.isSelected());
                        checkbox.setSelected(!checkbox.isSelected());
                        repaint();
                    } else if(e.getButton() == MouseEvent.BUTTON3) {
                        ContextMenu pum = new ContextMenu(cbl);
                        pum.show(e.getComponent(), e.getX(), e.getY());
                    }
                }
            }
        });
        this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    }

    protected class CheckboxCellRenderer implements ListCellRenderer {

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index,
                boolean isSelected, boolean cellHasFocus) {
            Data v = (Data) value;
            JCheckBox checkbox = new JCheckBox(v.getS(), v.isSelected());
            checkbox.setBackground(isSelected ? getSelectionBackground() : getBackground());
            checkbox.setBorderPainted(true);
            checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder")
                    : noFocusBorder);
            return checkbox;
        }
    }

    public int getSelection() {
        return this.selection;
    }

    public class ContextMenu extends JPopupMenu {

        private JMenuItem deleteItem;
        private JMenuItem addItem;
        private CheckBoxList cbl;

        public ContextMenu(CheckBoxList cbl) {
            this.cbl = cbl;
            this.deleteItem = new JMenuItem("Delete");
            this.deleteItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    JMenuItem jmi = (JMenuItem) e.getSource();
                    ContextMenu cm = (ContextMenu) jmi.getParent();
                    Model m = (Model) cm.cbl.getModel();
                    m.remove((Data) m.getElementAt(cm.cbl.getSelection()));
                    cm.cbl.repaint();
                }
            });
            this.add(deleteItem);

            this.addItem = new JMenuItem("Add new");
            this.addItem.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    JMenuItem jmi = (JMenuItem) e.getSource();
                    ContextMenu cm = (ContextMenu) jmi.getParent();
                    ((Model) cm.cbl.getModel()).add(new Data("Added :)"));
                    cm.cbl.repaint();
                }
            });
            this.add(addItem);
        }
    }
}

模型。爪哇

package misc;

import java.util.ArrayList;
import java.util.List;

import javax.swing.ListModel;
import javax.swing.event.ListDataListener;

public class Model implements ListModel {

    private List<Data> data = new ArrayList<Data>();

    @Override
    public void addListDataListener(ListDataListener l) {}

    @Override
    public Object getElementAt(int index) {
        return data.get(index);
    }

    @Override
    public int getSize() {
        return data.size();
    }

    @Override
    public void removeListDataListener(ListDataListener l) {}

    public void add(Data string) {
        this.data.add(string);
    }

    public void remove(Data d) {
        data.remove(d);
    }
}

数据。爪哇

package misc;

public class Data {

    private String s;
    private boolean selected = false;

    public Data(String s) {
        super();
        this.s = s;
    }

    public String getS() {
        return this.s;
    }

    public void setS(String s) {
        this.s = s;
    }

    public boolean isSelected() {
        return this.selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    @Override
    public String toString() {
        return "Data [s=" + this.s + ", isSelected=" + this.selected + "]";
    }

}

梅因。爪哇

package misc;

import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JScrollPane;

public class Main {

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setPreferredSize(new Dimension(500,200));
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        Model m = new Model();
        m.add(new Data("test1"));
        m.add(new Data("test2"));
        CheckBoxList cbl = new CheckBoxList(m);
        JScrollPane jsp = new JScrollPane(cbl);
        f.add(jsp);
        f.pack();
        f.setVisible(true);
    }
}

共 (2) 个答案

  1. # 1 楼答案

    问题来自ListModel的实现,其中没有实现addListDataListener和removeListDataListener,也没有触发适当的模型事件来通知它们

    只需在ListModel中添加以下内容,它就会工作得更好:

        private List<ListDataListener> listeners = new ArrayList<ListDataListener>();
    
        @Override
        public void addListDataListener(ListDataListener l) {
            listeners.add(l);
        }
    
        @Override
        public void removeListDataListener(ListDataListener l) {
            listeners.remove(l);
        }
    
        public void add(Data string) {
            this.data.add(string);
            ListDataEvent addition = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, data.size() - 1, data.size() - 1);
            for (ListDataListener l : listeners) {
                l.intervalAdded(addition);
            }
        }
    
        public void remove(Data d2) {
            data.remove(d2);
            ListDataEvent removal = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, data.size(), data.size());
            for (ListDataListener l : listeners) {
                l.intervalRemoved(removal);
            }
        }
    

    可能考虑扩展或直接使用{{CD2}}来处理所有这些。

  2. # 2 楼答案

    我认为您必须在模型中实现数据侦听器。可以通过Swing添加侦听器,当某些内容发生更改时,他们希望得到通知