12

如果单击 JList 上的选定索引,我希望它取消选择。换句话说,单击索引实际上会切换它们的选择。看起来不支持,所以我尝试了

list.addMouseListener(new MouseAdapter()
{
   public void mousePressed(MouseEvent evt)
   {
      java.awt.Point point = evt.getPoint();
      int index = list.locationToIndex(point);
      if (list.isSelectedIndex(index))
         list.removeSelectionInterval(index, index);
   }
});

这里的问题是,这是在JList 已经对鼠标事件起作用之后调用的,因此它取消选择所有内容。因此,我尝试删除所有 JList 的 MouseListeners,添加我自己的,然后将所有默认侦听器添加回来。这不起作用,因为 JList 在我取消选择索引后会重新选择它。无论如何,我最终想出的是

MouseListener[] mls = list.getMouseListeners();
for (MouseListener ml : mls)
   list.removeMouseListener(ml);
list.addMouseListener(new MouseAdapter()
{
   public void mousePressed(MouseEvent evt)
   {
      java.awt.Point point = evt.getPoint();
      final int index = list.locationToIndex(point);
      if (list.isSelectedIndex(index))
         SwingUtilities.invokeLater(new Runnable()
         {
            public void run()
            {
               list.removeSelectionInterval(index, index);
            }
         });
   }
});
for (MouseListener ml : mls)
   list.addMouseListener(ml);

……那行得通。但我不喜欢它。有没有更好的办法?

4

6 回答 6

12

在此处查看示例“ListSelectionModel:启用切换选择模式”:http: //java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html

我已经为多选列表框稍微修改了它(将 setSelectionInterval 更改为 addSelectionInterval)并消除了重新选择的问题,如果您单击以取消选择并在鼠标按下时移动鼠标(移动了gestureStarted 检查添加和消除)。

objList.setSelectionModel(new DefaultListSelectionModel() {
    private static final long serialVersionUID = 1L;

    boolean gestureStarted = false;

    @Override
    public void setSelectionInterval(int index0, int index1) {
        if(!gestureStarted){
            if (isSelectedIndex(index0)) {
                super.removeSelectionInterval(index0, index1);
            } else {
                super.addSelectionInterval(index0, index1);
            }
        }
        gestureStarted = true;
    }

    @Override
    public void setValueIsAdjusting(boolean isAdjusting) {
        if (isAdjusting == false) {
            gestureStarted = false;
        }
    }

});
于 2012-02-08T15:36:45.707 回答
5

这个怎么样?

import javax.swing.DefaultListSelectionModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.ListSelectionModel;

public class A {
    public static void main(String[] args) {
        JFrame f = new JFrame("Test");
        final JList list = new JList(new String[] {"one","two","three","four"});
        list.setSelectionModel(new DefaultListSelectionModel(){


            @Override
            public void setSelectionInterval(int index0, int index1) {
                if (index0==index1) {
                    if (isSelectedIndex(index0)) {
                        removeSelectionInterval(index0, index0);
                        return;
                    }
                }
                super.setSelectionInterval(index0, index1);
            }

            @Override
            public void addSelectionInterval(int index0, int index1) {
                if (index0==index1) {
                    if (isSelectedIndex(index0)) {
                        removeSelectionInterval(index0, index0);
                        return;
                    }
                super.addSelectionInterval(index0, index1);
                }
            }

        });
        f.getContentPane().add(list);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }

}

它有效,但请注意一个副作用......例如,如果您将模式设置为多选择,例如:

list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION );

您不能通过鼠标拖动选择多个对象。Ctrl(或 shift)单击有效。我确信它可以修复,但我假设你问过这个单选列表......如果不修改你的问题,我们可以开始考虑解决多选问题。

于 2010-03-28T01:50:18.090 回答
3

我知道这个问题已经有了一个公认的答案,但我想我会扩大一点,因为我最终在这个任务上停留了几个小时。

我试图为选定的项目实现单击取消选择操作,但我的列表实现需要使用单选模式,由

JList jlist = new JList(new DefaultListModel());
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

不幸的是,这导致了许多 SO 问题的点击取消选择问题的许多解决方案的异常和冗余调用,包括上面FuryComptuers的这个答案。由于 in 中的代码,特别是and方法中的代码,它回调该方法,导致循环调用导致(显然)异常。这个“问题”代码如下所示。DefaultListSelectionModel.classaddSelectionInterval(int index0, int index1)removeSelectionInterval(int index0, int index1)setSelectionInterval(int index0, int index1)

 // If we only allow a single selection, channel through
    // setSelectionInterval() to enforce the rule.
    if (getSelectionMode() == SINGLE_SELECTION) {
        setSelectionInterval(index0, index1);
        return;
    }

Sawas Dalkitsis回答解决了这个问题,但是在选定项目上拖动鼠标时仍然会表现得很奇怪(在拖动鼠标时,选定的项目会一遍又一遍地选择和取消选择)。这似乎不是问题,但是(显然)我的手颤抖,单击时鼠标的轻微移动会导致不必要的行为。我结合了 Sawas Dalkitsis的 答案FuryComptuers答案来获得以下代码,这似乎可以按预期工作:

    JList jlist = new JList(new DefaultListModel());
    jList.setSelectionModel(new DefaultListSelectionModel() {
        private static final long serialVersionUID = 1L;

        boolean gestureStarted = false;

        @Override
        public void setSelectionInterval(int index0, int index1) {
            if(!gestureStarted){
            if (index0==index1) {
                if (isSelectedIndex(index0)) {
                    removeSelectionInterval(index0, index0);
                    return;
                }
            }
            super.setSelectionInterval(index0, index1);
            }
            gestureStarted = true;
        }

        @Override
        public void addSelectionInterval(int index0, int index1) {
            if (index0==index1) {
                if (isSelectedIndex(index0)) {
                    removeSelectionInterval(index0, index0);
                    return;
                }
            super.addSelectionInterval(index0, index1);
            }
        }

        @Override
        public void setValueIsAdjusting(boolean isAdjusting) {
            if (isAdjusting == false) {
                gestureStarted = false;
            }
        }

    });
    jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

注意:我没有ListSelectionModel.SINGLE_INTERVAL_SELECTIONSawas Dalkitsis那样检查这个,所以在这种情况下实现它时要小心。

于 2012-12-10T19:30:33.953 回答
0

我扩展了 FuryComptuers答案以支持多选,并修复了setSelectionInterval直接调用时不起作用的问题。

public class ToggleableListSelectionModel extends DefaultListSelectionModel {
    private static final long serialVersionUID = 1L;

    private boolean mGestureStarted;

    @Override
    public void setSelectionInterval(int index0, int index1) {
        // Toggle only one element while the user is dragging the mouse
        if (!mGestureStarted) {
            if (isSelectedIndex(index0)) {
                super.removeSelectionInterval(index0, index1);
            } else {
                if (getSelectionMode() == SINGLE_SELECTION) {
                    super.setSelectionInterval(index0, index1);
                } else {
                    super.addSelectionInterval(index0, index1);
                }
            }
        }

        // Disable toggling till the adjusting is over, or keep it
        // enabled in case setSelectionInterval was called directly.
        mGestureStarted = getValueIsAdjusting();
    }

    @Override
    public void setValueIsAdjusting(boolean isAdjusting) {
        super.setValueIsAdjusting(isAdjusting);

        if (isAdjusting == false) {
            // Enable toggling
            mGestureStarted = false;
        }
    }   
}
于 2014-05-09T13:23:46.137 回答
0

您始终可以使用 ListSelectionListener 而不是破译单击的点,然后将其转换为选定的项目。

http://java.sun.com/docs/books/tutorial/uiswing/examples/events/index.html#ListSelectionDemo

http://java.sun.com/docs/books/tutorial/uiswing/events/listselectionlistener.html

http://java.sun.com/docs/books/tutorial/uiswing/examples/events/ListSelectionDemoProject/src/events/ListSelectionDemo.java

在上面的java文件链接中,有一个可以很容易地改进为“取消选择”的实现:)

于 2010-03-27T13:33:54.803 回答
0

Nick Dandoulakis 的回答对我来说不太适用,在按下 时使用鼠标单击一次选择多个项目Shift

当使用带有或的鼠标单击选择项目时,以下ListSelectionModel行为与我预期的一样。ShiftCtrl

此外,按住Shift + Ctrl并按下任一→</kbd> or ←</kbd> selects items the way I want it to.

public static class ToggleableListSelectionModel extends DefaultListSelectionModel {
        private static final long serialVersionUID = 1L;

        @Override
        public void setSelectionInterval(int startIndex, int endIndex) {
            if (startIndex == endIndex) {
                if (multipleItemsAreCurrentlySelected()) {
                    clearSelection();
                }
                if (isSelectedIndex(startIndex)) {
                    clearSelection();
                }
                else {
                    super.setSelectionInterval(startIndex, endIndex);
                }
            }
            // User selected multiple items
            else {
                super.setSelectionInterval(startIndex, endIndex);
            }
        }

        private boolean multipleItemsCurrentlyAreSelected() {
            return getMinSelectionIndex() != getMaxSelectionIndex();
        }
    }
于 2015-07-10T08:49:32.053 回答