【问题标题】:ListSelectionListener does not fire events when calling setSelected methodsListSelectionListener 在调用 setSelected 方法时不会触发事件
【发布时间】:2020-10-02 13:54:23
【问题描述】:

这里的第一个问题,希望我做对了。

下面是我的问题的一个最小示例,我很快就为我的项目挑选了代表。我为包含一些对象的 JList 创建了一个自定义渲染器(在示例中,我使用字符串进行说明)。我的问题是,据我所知,如果我将 ListSelectionListener 添加到列表中,setSelected...() 方法系列不会触发触发条件 if(e.getValueIsAdjusting()) 的事件。

在下面的示例中,问题在启动程序时立即显而易见:即使在将 JLabel 的选定文本指定为“无”之后调用 list.setSelectedIndex(2);,它也不会改变,直到您(用户)单击列表项.事实上,它必须与当前选择的项目不同。

我想要这个功能,这样我的程序流程将是,在用户从列表中添加/删除项目后,一旦所选列表项目发生更改,“视图”就会立即更新。

是我做错了什么,还是我的处理方法不正确?

谢谢。 :)

import java.awt.BorderLayout;
import java.beans.*;
import javax.swing.*;

public class Example implements PropertyChangeListener {
    String ITEM_SELECTED = "Item Selected";
    String DELETE_SELECTED = "Delete Selected";
    PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    JLabel selected;

    JList<String> list;
    DefaultListModel<String> model;

    public static void main(String[] args) {
        new Example();
    }

    public Example() {
        JFrame frame = new JFrame();
        JPanel mainPanel = new JPanel(new BorderLayout());

        model = new DefaultListModel<>();
        model.addElement("Entry 1");
        model.addElement("Entry 2");
        model.addElement("Entry 3");
        model.addElement("Entry 4");
        model.addElement("Entry 5");

        list = new JList<>(model);

        selected = new JLabel("Currently selected: none");
        list.setSelectedIndex(2);

        list.addListSelectionListener(e -> {
                if(e.getValueIsAdjusting()) {
                    pcs.firePropertyChange(ITEM_SELECTED, null, null);
                }
            }
        );

        JButton removeItem = new JButton("Remove item");

        removeItem.addActionListener(e -> {
                pcs.firePropertyChange(DELETE_SELECTED, null, null);
            }
        );

        mainPanel.add(new JScrollPane(list), BorderLayout.WEST);
        mainPanel.add(removeItem, BorderLayout.NORTH);

        mainPanel.add(selected, BorderLayout.CENTER);       

        pcs.addPropertyChangeListener(this);

        frame.add(mainPanel);
        frame.setSize(300, 400);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        String event = (String) evt.getPropertyName();

        if (event.equals(ITEM_SELECTED)) {
            selected.setText("Currently selected: " + list.getSelectedValue());
        }

        if (event.equals(DELETE_SELECTED)) {
            int selectedIndex = list.getSelectedIndex();
            model.removeElement(list.getSelectedValue());

            if (selectedIndex > 0)
                list.setSelectedIndex(selectedIndex-1);
            else if (selectedIndex == 0)
                list.setSelectedIndex(selectedIndex);
        }
    }
}

【问题讨论】:

  • 我的处理方法有误吗? - 不确定您真正想要做什么。我不明白对 PropertyChangeListener 的需求。您已经在 ListSelectionListener 中处理了选择更改事件,为什么还要添加另一个间接级别。只需将当前在 PropertyChangeListener 中的处理逻辑添加到 ListSelectionListener 中即可。 “删除”逻辑也是如此。你已经有一个 ActionListener,为什么还要涉及 PropertyChangeListener?
  • 阅读 How to Use Lists 上的 Swing 教程,了解为 JList 动态添加/删除项目的工作示例。
  • 包含属性更改侦听器是为了让给定的示例模仿我的项目。在那里,所有东西都被设计成模块化并遵循 MVC,所以这个例子实际上是用至少 2 个独立的类编写的。我在这里写的所有东西都在一个类中,以便于复制粘贴和测试。我理解冗余。 :)

标签: java swing model-view-controller listener propertychangelistener


【解决方案1】:

e.getValueIsAdjusting() 方法检查值是否仍在调整中。在您的情况下,list.setSelectedIndex(2) 触发的事件看起来会让 e.getValueIsAdjusting() 返回 false。

你可以通过做相反的检查来解决这个问题:!e.getValueIsAdjusting()

然后,这将检查响应的任何更改是否是该事件链的最后一个。

【讨论】:

  • 是的,做到了。不利的一面是,修复这个引入了很多我需要修复的新错误,但我想这就是编程。谢谢!
  • @TomH 不确定如何完全解决问题。您发布的代码甚至没有将 ListSelectionListener 添加到 JList 并且 PropertyChangeListener 还没有添加到 PropertyChangeSupport,因此当索引设置为 2 时不会生成这些事件。
  • 我不确定你的意思。 JList 和按钮将侦听器作为 lambda 添加到其中,并且类本身实现了 PropertyChangeListener 并在接近尾声时添加到 PCS 对象 (pcs.addPropertyChangeListener(this);)。不过,我确实意识到我在最后添加了一个冗余方法(试图最小化地复制我的项目)。我刚刚摆脱了它。
  • 您是对的,但是,添加否定并不能修复 JLabel 中显示的初始索引,但它确实解决了删除一个项目并重新选择另一个项目不会更改标签的问题。就我的目的而言,后者足以让我继续我的项目,但如果您有建议让初始选择也触发一个事件,我会全神贯注。 :)
  • 我不确定你的意思 - 查看代码的逻辑顺序 1) 设置索引 2) 添加选择监听器 3) 添加正确的更改监听器.如果尚未添加侦听器,如何设置索引生成事件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
  • 2012-11-25
  • 2013-06-19
相关资源
最近更新 更多