JList - отменить выбор при нажатии на уже выбранный элемент
Если щелкнуть выбранный индекс в 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 уже воздействовал на событие мыши, поэтому он отменяет выбор всего. Затем я попытался удалить все MouseListeners JList, добавить свои собственные, а затем добавить всех слушателей по умолчанию обратно. Это не сработало, так как 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);
... и это работает. Но мне это не нравится. Есть ли способ лучше?
6 ответов
Глядя на пример "ListSelectionModel: включение режима выбора переключения" здесь: http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html
Я немного изменил его для списков с множественным выбором (изменил setSelectionInterval на addSelectionInterval) и устранил проблему с повторным выбором, если щелкнуть, чтобы отменить выбор и переместить мышь, когда мышь нажата (переместил проверку gestStarted для добавления и Удалить).
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;
}
}
});
Как насчет этого?
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) щелчок работает. Я уверен, что это можно исправить, но я предполагаю, что вы спрашивали об этом для отдельных списков выбора... Если не измените свой вопрос, и мы можем начать думать о решениях проблемы множественного выбора.
Я знаю, что на этот вопрос уже есть принятый ответ, но я подумал, что немного расширимся, так как я застрял на этой задаче на несколько часов.
Я пытался реализовать действие щелчка для отмены выбора для выбранных элементов, но моя реализация списка требует использования режима одиночного выбора, указанного в
JList jlist = new JList(new DefaultListModel());
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
К сожалению, это привело к исключениям и избыточным запросам для многих решений проблемы щелчка для отмены FuryComputers по многим вопросам SO, включая этот ответ от FuryComputers выше. Из-за кода в 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;
}
Savvas Dalkitsis решил эту проблему, но он все равно будет вести себя странно, если перетаскивать мышь на выбранный элемент (выбранный элемент будет выделяться и отменять выбор снова и снова при перетаскивании мыши). Это не кажется проблемой, но (по-видимому) у меня дрожит рука, и незначительные движения мыши при нажатии приводят к нежелательному поведению. Я объединил ответ FuryComputers Savvas Dalkitsis ответ FuryComputers, чтобы получить следующий код, который, кажется, работает как нужно:
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_SELECTION
Savvas Dalkitsis делал Savvas Dalkitsis, будьте осторожны при его реализации в этом случае.
Я расширил ответ 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;
}
}
}
Вы всегда можете использовать ListSelectionListener вместо того, чтобы расшифровывать нажатую точку и затем переводить ее в выбранный элемент.
http://java.sun.com/docs/books/tutorial/uiswing/examples/events/index.html
http://java.sun.com/docs/books/tutorial/uiswing/events/listselectionlistener.html
В приведенной выше ссылке на файл Java есть реализация, которая может быть легко улучшена, чтобы сделать "отмену выбора":)
Ответ Ника Дандулакиса мне не помог, когда я выбирал несколько элементов одновременно, щелкая мышью и нажимая Shift.
Следующие ListSelectionModel
ведет себя так, как и ожидалось при выборе элементов с помощью щелчков мыши с Shift или Ctrl.
Кроме того, удерживая 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();
}
}