Как предотвратить jlist от выбора за пределами границ ячейки?
" есть ли способ запретить JList выбирать последний элемент, когда пользователь нажимает под ним в списке?"
вот вопрос, который кто-то задал здесь и у меня такая же проблема. Этот парень нашел так себе решение (переопределив processMouseEvent ()), но я хочу знать, есть ли лучший/более элегантный способ сделать это.
[Edit]
Ok, подробнее. Если у вас есть JList и есть свободное место любая ячейка / элемент, и вы нажимаете это пространство, затем выбирается последний элемент в JList.
для реального примера попробуйте это JList Swing учебник пример, нажать пробел и проследи, чтобы Ролло выбрали.
2 ответов
см.https://forums.oracle.com/forums/thread.jspa?threadID=2206996
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
public class TestJList {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JList list = new JList(new Object[] { "One", "Two", "Three" }) {
@Override
public int locationToIndex(Point location) {
int index = super.locationToIndex(location);
if (index != -1 && !getCellBounds(index, index).contains(location)) {
return -1;
}
else {
return index;
}
}
};
list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
JList list = (JList) e.getSource();
if (list.locationToIndex(e.getPoint()) == -1 && !e.isShiftDown()
&& !isMenuShortcutKeyDown(e)) {
list.clearSelection();
}
}
private boolean isMenuShortcutKeyDown(InputEvent event) {
return (event.getModifiers() & Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()) != 0;
}
});
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(list));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
глядя на стек вызовов, вы не можете делать то, что хотите, не возясь с AWT-событиями:
Thread [AWT-EventQueue-0] (Suspended (breakpoint at line 384 in DefaultListSelectionModel))
DefaultListSelectionModel.changeSelection(int, int, int, int, boolean) line: 384
DefaultListSelectionModel.changeSelection(int, int, int, int) line: 415
DefaultListSelectionModel.setSelectionInterval(int, int) line: 459
TestJList(JList<E>).setSelectionInterval(int, int) line: 2067
BasicListUI$Handler.adjustSelection(MouseEvent) line: 2739
BasicListUI$Handler.mousePressed(MouseEvent) line: 2695
AWTEventMulticaster.mousePressed(MouseEvent) line: 280
TestJList(Component).processMouseEvent(MouseEvent) line: 6502
TestJList(JComponent).processMouseEvent(MouseEvent) line: 3321
TestJList.processMouseEvent(MouseEvent) line: 24
TestJList(Component).processEvent(AWTEvent) line: 6270
TestJList(Container).processEvent(AWTEvent) line: 2229
TestJList(Component).dispatchEventImpl(AWTEvent) line: 4861
TestJList(Container).dispatchEventImpl(AWTEvent) line: 2287
TestJList(Component).dispatchEvent(AWTEvent) line: 4687
LightweightDispatcher.retargetMouseEvent(Component, int, MouseEvent) line: 4832
LightweightDispatcher.processMouseEvent(MouseEvent) line: 4489
LightweightDispatcher.dispatchEvent(AWTEvent) line: 4422
JFrame(Container).dispatchEventImpl(AWTEvent) line: 2273
JFrame(Window).dispatchEventImpl(AWTEvent) line: 2713
JFrame(Component).dispatchEvent(AWTEvent) line: 4687
EventQueue.dispatchEventImpl(AWTEvent, Object) line: 707
EventQueue.access0(EventQueue, AWTEvent, Object) line: 101
EventQueue.run() line: 666
EventQueue.run() line: 664
AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]
ProtectionDomain.doIntersectionPrivilege(PrivilegedAction<T>, AccessControlContext, AccessControlContext) line: 76
ProtectionDomain.doIntersectionPrivilege(PrivilegedAction<T>, AccessControlContext) line: 87
EventQueue.run() line: 680
EventQueue.run() line: 678
Вы можете реализовать свой собственный ListUI, а затем делать все, что хотите (включая предотвращение этого нежелательного поведения), но я бы не рекомендовал идти по этому пути.
для чего это стоит (это делается путем переопределения методов processXXXEvent), вот небольшой фрагмент, который я на самом деле не нахожу уродливым и который предотвращает выбор объектов при нажатии за их пределами:
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TestJList {
private JList list;
protected void initUI() {
JFrame frame = new JFrame("test");
list = new JList(new Object[] { "Hello", "World", "!" }) {
private boolean processEvent(MouseEvent e) {
int index = list.locationToIndex(e.getPoint());
return index > -1 && list.getCellBounds(index, index).contains(e.getPoint());
}
@Override
protected void processMouseEvent(MouseEvent e) {
if (processEvent(e)) {
super.processMouseEvent(e);
}
}
@Override
protected void processMouseMotionEvent(MouseEvent e) {
if (processEvent(e)) {
super.processMouseMotionEvent(e);
}
}
};
list.setVisibleRowCount(10);
frame.add(new JScrollPane(list));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestJList().initUI();
}
});
}
}