java JList - 单击已选择的项目时取消选择
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2528344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JList - deselect when clicking an already selected item
提问by Pete
If a selected index on a JList is clicked, I want it to de-select. In other words, clicking on the indices actually toggles their selection. Didn't look like this was supported, so I tried
如果单击 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);
}
});
The problem here is that this is being invoked afterJList has already acted on the mouse event, so it deselects everything. So then I tried removing all of JList's MouseListeners, adding my own, and then adding all of the default listeners back. That didn't work, since JList would reselect the index after I had deselected it. Anyway, what I eventually came up with is
这里的问题是,这是在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);
... and that works. But I don't like it. Is there a better way?
......这有效。但我不喜欢。有没有更好的办法?
回答by FuryComputers
Looking at the Example "ListSelectionModel: Enabling Toggle Selection Mode" here: http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html
在此处查看示例“ListSelectionModel:启用切换选择模式”:http: //java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html
I have modified it slightly for multi-select list boxes (changed setSelectionInterval to addSelectionInterval) and eliminated a problem with re-selection if you click to de-select and move your mouse while the mouse is down (moved the gestureStarted check for both add and remove).
我已经为多选列表框稍微修改了它(将 setSelectionInterval 更改为 addSelectionInterval)并消除了重新选择的问题,如果您在鼠标按下时单击取消选择并移动鼠标(移动了手势开始检查添加和消除)。
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;
}
}
});
回答by Savvas Dalkitsis
How about this?
这个怎么样?
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);
}
}
It works but note one side effect... If you set the mode to multi selction like this for instance:
它有效,但请注意一个副作用......如果您将模式设置为多选,例如:
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION );
you cannot select multiple objects via mouse drag. Ctrl (or shift) click works. I'm sure it can be fixed but i assume you asked this for single selection lists... If not modify your question and we can start thinking for solutions to the multiple selection problem.
您不能通过鼠标拖动选择多个对象。Ctrl(或Shift)单击有效。我确定它可以修复,但我假设你问这个是为了单选列表......如果不修改你的问题,我们就可以开始思考多选问题的解决方案。
回答by shawmanz32na
I know that this question already has an accepted answer, but I thought that I'd expand a bit, since I ended up stuck on this task for a few hours.
我知道这个问题已经有一个公认的答案,但我认为我会扩展一点,因为我最终在这个任务上停留了几个小时。
I was trying to implement a click-to-deselect action for selected items, but my list implementation requires the use of Single-Selection mode, specified by
我试图为所选项目实现点击取消选择操作,但我的列表实现需要使用单选模式,由
JList jlist = new JList(new DefaultListModel());
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
Unfortunately, this led to exceptions and redundant calls for many of the solutions for the click-to-deselect problem on many SO questions, including this answerby FuryComptuersabove. Due to code in DefaultListSelectionModel.class, specifically in the addSelectionInterval(int index0, int index1)and removeSelectionInterval(int index0, int index1)methods, which calls back to the setSelectionInterval(int index0, int index1)method, caused a circular call that leads to (obviously) exceptions. This "problem" code can be seen below.
不幸的是,这导致异常和重复的调用了很多很多的SO问题,包括点击到取消问题的解决方案此答案由FuryComptuers以上。由于 中的代码DefaultListSelectionModel.class,特别是addSelectionInterval(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' answersolved this problem, but would still act weird when dragging the mouse on a selected item (the selected item will select and de-select itself over and over while dragging the mouse). This wouldn't seem like a problem, but (apparently) I have a shaky hand, and minor mouse movements while clicked resulted in unwanted behavior. I combined Sawas Dalkitsisanswerand FuryComptuers's answerto get the following code, which seems to work as desired:
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);
Note: I didn't check this against the ListSelectionModel.SINGLE_INTERVAL_SELECTION, as Sawas Dalkitsisdid, so use caution if implementing it in that case.
注意:我没有ListSelectionModel.SINGLE_INTERVAL_SELECTION像Sawas Dalkitsis那样针对 进行检查,因此如果在这种情况下实施它,请务必小心。
回答by Nick Dandoulakis
I extended FuryComptuersanswer to support multiple selection, and fixed an issue where setSelectionIntervaldidn't work if it was called directly.
我扩展了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;
}
}
}
回答by Matthias Braun
Nick Dandoulakis' answerdidn't quite work for me when selecting multiple items at once using a mouse click while pressing Shift.
Nick Dandoulakis 的回答在按下 的同时使用鼠标单击一次选择多个项目时对我来说不太适用Shift。
The following ListSelectionModelbehaves as I'd expect it when selecting items using mouseclicks with Shiftor Ctrl.
在ListSelectionModel使用鼠标单击Shift或选择项目时,以下行为与我期望的一样Ctrl。
Also, holding down Shift + Ctrland pressing either →or ←selects items the way I want it to.
此外,按住Shift + Ctrl并按下任一→或←选择项目,我希望它的方式。
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();
}
}
回答by Kannan Ekanath
You could always the ListSelectionListener instead of deciphering the point clicked and then translating it to the item selected.
您始终可以使用 ListSelectionListener 而不是破译单击的点,然后将其转换为选定的项目。
http://java.sun.com/docs/books/tutorial/uiswing/examples/events/index.html#ListSelectionDemo
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/events/listselectionlistener.html
In the above link for java file there is an implementation which can be easily improved to do "deselection" :)
在上面的 java 文件链接中,有一个可以轻松改进以进行“取消选择”的实现:)

