ListSelectionModel.insertIndexInterval()方法具体是做什么的?

3

我正在尝试编写自己的ListSelectionModel实现,目前我在尝试实现insertIndexInterval时遇到了困难。我不理解Sun/Oracle的DefautListSelectionModel实现中这个方法的结果。以下是一个示例:

ListSelectionModel model = new DefaultListSelectionModel();
model.setSelectionInterval(3, 5);
model.addListSelectionListener(new ListSelectionListener()
{
    public void valueChanged(ListSelectionEvent e)
    {
        System.out.println("Changed range reported by event: " +
            e.getFirstIndex() + "-" + e.getLastIndex());
    }
});

System.out.print("Selected indices before insert: ");
for (int i = model.getMinSelectionIndex(); i <= model.getMaxSelectionIndex(); i++)
    if (model.isSelectedIndex(i)) System.out.print(i + " ");
System.out.println();

model.insertIndexInterval(3, 3, true);  

System.out.print("Selected indices after insert: ");
for (int i = model.getMinSelectionIndex(); i <= model.getMaxSelectionIndex(); i++)
    if (model.isSelectedIndex(i)) System.out.print(i + " ");
System.out.println();

当您运行此代码时,您将获得以下输出:
Selected indices before insert: 3 4 5 
Changed range reported by event: 3-8
Selected indices after insert: 3 4 5 6 7 8 

最初的选择范围是3-5,在插入新索引时扩展为3-8。但是因为已经选中了3-5,所以实际更改的只有6-8。为什么事件告诉我范围为3-8的内容已被更改呢?当你将insertIndexInterval调用更改为以下内容时,情况变得更加混乱:

model.insertIndexInterval(3, 3, false);  

现在的输出结果是这样的:
Selected indices before insert: 3 4 5 
Changed range reported by event: 5-8
Selected indices after insert: 3 4 5 6 7 8 

我不知道为什么报告的变化是5-8。

这个方法的API文档太简短了,无法理解其中发生了什么。特别是这个before参数对我来说是一个谜,因为它对选择没有任何影响,但似乎对事件和引线和锚点索引有一些影响。

我甚至不能为我的实现编写单元测试,因为我根本不知道预期结果。

那么,有人能详细解释一下这个方法(尤其是before标志)正在做什么,以及它对选择模型和ListSelectionEvent的副作用吗?

2个回答

4

当向数据模型添加新数据时使用它(因此当前选择的索引应该移动)。如果2表示“新添加并选择”,那么您的输出将是:

[0,0,0,1,1,1,0,0,0,0] == [3A,4,5L]
-> add after [0,0,0,1,2,2,2,1,1,0] == [3A,4,5,6,7,8L]
-> add before [0,0,0,2,2,2,1,1,1,0] == [3,4,5,6A,7,8L]

在这里看到的是DefaultListSelectionModel的一个特性*——在当前选择中添加索引,自动扩展选择。

例如,从选择了索引1开始,在索引3处插入三行:

[1,0,0,0,0,0,0,0,0,0]
-> add after [1,0,0,0,0,0,0,0,0,0]

请注意,您选择的表示方式是误导性的,其中的零实际上并不存在。更好的打印选择状态的方式如下所示:
private static void printSelection(ListSelectionModel model) {
    System.out.print("[");
    for (int i = model.getMinSelectionIndex(); i <= model.getMaxSelectionIndex(); i++) {
        if(i > model.getMinSelectionIndex()) {
            System.out.print(",");
        }
        if(model.isSelectedIndex(i)) {
            System.out.print(i);
            if(i == model.getAnchorSelectionIndex()) {
                System.out.print("A");
            }
            if(i == model.getLeadSelectionIndex()) {
                System.out.print("L");
            }
        }
    }
    System.out.println("]");
}

*) DefaultListSelectionModel#insertIndexInterval的文档与接口不同,详见http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4700643http://java.net/jira/browse/SWINGX-272

是的,我知道这些零实际上并不存在。只是以这种方式进行比较更容易。但我仍然不明白。事件绑定到选择模型,而不是数据模型。在插入新数据之前,索引3-5已经被选中,因此唯一真正的变化(对于选择模型而言,而不是数据模型)是6-8的额外选择范围。但报告的更改是3-8(当before=true时),5-8(当before=false时)。特别是这个5-8到目前为止毫无意义。 - kayahr
1
是的,这样就解释了3-8(因为1已经移动了,2已经添加了),但是当使用before=false时,如何解释报告的5-8范围呢?当将其可视化为三状态时,它必须是6-8,因为三个1不会移动,而三个2插入到索引6而不是5。 - kayahr
1
顺便提一句:如果在索引3之后插入,则应该是0001222110而不是0001112220,对吗?文档中说“在索引之前/之后插入长度索引”。 - kayahr
1
假设你的列表有6个项目,选择了3、4、5。如果在第3行之前插入3行,则该选择将上移至6、7、8。你看到这些事件范围(我猜你期望在插入后看到6-8)的原因是主要选择索引从5更改为8,这意味着现在应该在第8行上绘制焦点,而不是第5行。奇怪的是,锚点在之前从3更改为6,所以你得到了3-8的范围。 - Walter Laan
@kayahr 啊...很好的发现,没注意到5和6的区别,这就是我一直想知道为什么你感到惊讶的原因 :-) - kleopatra
显示剩余2条评论

-2

编辑说明:希望我们讨论的是JList,而不是JTable,其余内容在通知中

你能否使用这个SSCCE,并清晰地演示你在ListSelectionModelListeSelectionMode和相关代码解决方法方面遇到的问题,注意这个Listener只有一个dimensional或者directional

import java.awt.Component;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import javax.swing.*;

public class Ctrl_Down_JList {

    private static void createAndShowUI() {
        String[] items = {"Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"};
        JList myJList = new JList(items) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void processMouseEvent(MouseEvent e) {
                int modifiers = e.getModifiers() | InputEvent.CTRL_MASK;
                // change the modifiers to believe that control key is down
                int modifiersEx = e.getModifiersEx() | InputEvent.CTRL_MASK;
                // can I use this anywhere?  I don't see how to change the modifiersEx of the MouseEvent
                MouseEvent myME = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), modifiers, e.getX(),
                        e.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton());
                super.processMouseEvent(myME);
            }
        };
        JFrame frame = new JFrame("Ctrl_Down_JList");
        frame.getContentPane().add(new JScrollPane(myJList));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowUI();
            }
        });
    }

@Walter Laan,你说得对,但是如果不知道SelectionMode,为什么要费心呢?那么事情可以像你在答案中描述的那样简单,+1分为了费心,编辑和其余内容请看您答案下的评论 :-) - mKorbel
我已经添加了一个完整的代码示例。希望它足够清楚地展示了我的问题。 - kayahr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接