Java JTree valueChanged Событие перед MouseEvent
Вот ситуация, у меня есть jFrame с панелью с вкладками, а внутри вкладок у меня есть пара jTables и jTree. Я хочу иметь возможность связать выбор между таблицами и деревом в зависимости от того, использует ли пользователь Ctrl/ Shift + щелчок вместо обычного щелчка. (Если вы удерживаете Ctrl и щелкаете в первой таблице / дереве, это добавляет к общему выбору, если вы используете регулярное нажатие, оно очищает выборки в других таблицах / дереве). В настоящее время у меня проблема с компонентом Java jTree. Я добавил TreeSelectionListener и MouseListener с классом, который реализует оба интерфейса, назовите его MyBigListener; т.е.
MyBigListener listener = new MyBigListener();
jTree1.addMouseListener( listener );
jTree1.addTreeSelectionListener( listener );
MyBigListener implements TreeSelectionListener, MouseListener {
private boolean chained = false;
public synchronized setChained(boolean ch){
chained = ch;
}
public synchronized boolean isChained(){
return chained
}
public void valueChanged(TreeSelectionEvent e){
if(isChained()){ blah... }
}
public void mousePressed(MouseEvent e){
setChained(e.isControlDown() || e.isShiftDown());
}
}
Мой план состоял в том, чтобы установить логический флаг, если пользователь использует Ctrl/ Shift + щелчок, который я мог проверить во время valueChanged(TreeSelectionEvent e), реализованного слушателем выбора дерева. Я хочу иметь возможность обрабатывать события мыши до значения valueChanged TreeSelectionEvents, но проблема в том, что я получаю события мыши после события valueChanged treeSelection. Мне кажется странным, что я получаю изменение выделения до того, как сработает событие нажатия мыши, когда изменение выбора фактически инициируется нажатием мыши. (Я уже синхронизировал настройку логического флага, которая по иронии судьбы помогла выделить неправильный порядок событий.)
Я уже пробовал альтернативы, такие как добавление keyListener, но это не работает, когда фокус находится на отдельном кадре, что приводит меня в замешательство, когда пользователь удерживает Ctrl, а затем нажимает на jTree, заставляя его получать фокус и огонь любые события выбора valueChanged.
Любая помощь будет оценена, спасибо!
--EDIT-- @akf У меня есть отдельные jTables и jTrees в панели с вкладками, которые служат в качестве сводки / панели управления для данных в узловом графике. Я использую эти компоненты на панели с вкладками, чтобы сделать согласованный выбор для графика, отображаемого в отдельном jFrame. Каждый стол по отдельности отлично подходит для выбора, как и jTree. Это координация между панелями, что сложно. Пока что это нормально работает с компонентами jTable, потому что я запускаю новые выделения в результате MouseEvent, где я могу сказать, была ли кнопка shift / ctrl нажата, сформулировать свой новый выбор и передать его родительскому фрейму, который координирует выбор между всеми панели и отправляет окончательный выбор на график. Тем не менее, родитель должен знать, нужно ли ему связать выбор между панелями или раздавить остальные. С jTables снова все в порядке, потому что я запускаю изменения выбора в результате щелчка мышью. JTree - большая проблема, потому что я делаю некоторые принудительные выборы. Если вы нажмете на ветке, это заставит все листья в выбор. Мне нужно было реализовать TreeSelectionListener, чтобы сделать это, но получить только valueChanged(TreeSelectionEvent) для реализованных изменений. Я добавил mouseListener для прослушивания Ctrl+ щелчков и Shift + щелчков, но, очевидно, события не всегда происходят в одном и том же порядке... по крайней мере, до сих пор я получаю событие valueChanged до события mousePressed, поэтому проверяем, если ctrl+ клик по сообщениям после того, как выбор уже был изменен.
Прямо сейчас я публикую отложенное изменение выбора, а затем заставлю MouseListener захватить его и отправить его по цепочке, но если эти события не гарантированно произойдут в том же порядке, в какой-то момент произойдет сбой. Реализация задержки также теряет меня.
Спасибо за помощь.
--EDIT2-- @ykaganovich
Я думаю, что переопределение метода fireValueChanged ближе к правильному пути. В зависимости от моего определения того, какие действия должны вызывать "цепочку" выбора для других компонентов, мне нужно собрать некоторый контекст того, что происходит, прежде чем метод valuedChanged сработает. Это в основном означает называть его сам во всех случаях, когда я могу определить, что это значит, кто его запускает. Т.е. если событие мыши вызывает это и ctrl не работает, тогда установите то, что мне нужно установить (интерпретировать), а затем запустите. Если это изменится из-за события клавиатуры, снова установите то, что мне нужно установить, а затем запустите. Я не думаю, что TreeSelectionModel - это путь, потому что я все еще не буду знать, каковы были обстоятельства, когда событие произошло. Я думаю, что это означает, что мне нужно будет переписать части jTree, чтобы сделать это, но я думаю, я посмотрю, как это происходит. Благодарю.
3 ответа
Не делай так, переопредели JTree.fireValueChanged
вместо.
Попробуйте что-то вроде этого (не проверено):
class ChainedSelectionEvent extends TreeSelectionEvent {
ChainedSelectionEvent(TreeSelectionEvent e) {
super(e.newSource, e.paths, e.areNew, e.oldLeadSelectionPath, e.newLeadSelectionPath);
}
}
protected void fireValueChanged(TreeSelectionEvent e) {
if(chained) { // figure out separately
super.fireValueChanged(new ChainedSelectionEvent(e));
} else {
super.fireValueChanged(e);
}
}
Затем проверьте экземпляр ChainedSelectionEvent в вашем слушателе
РЕДАКТИРОВАТЬ
На самом деле, я думаю, что правильный способ сделать это - реализовать собственный TreeSelectionModel и переопределить там fireValueChanged. Если предположить, setSelectionPath(s)
методы подразумевают новый выбор, и add/removeSelectionPath(s)
подразумевая цепочку, вы могли бы различить два чисто. Мне не нравится явно слушать события клавиатуры или мыши, потому что есть несколько способов изменить выделение (например, если кто-то удерживает нажатой клавишу SHIFT и нажимает стрелку вниз, вы не получите событие мыши).
Вы можете получить событие мыши до или после события выбора дерева. Лучше не полагаться на такие заказы. Причина в том, что событие выбора дерева вызывается в ответ на событие мыши. Этот слушатель событий мыши вызывается до или после вашего слушателя? Может быть либо.
Подобные вещи тесно связаны с реализацией PL&F.
Ключом здесь является понимание того, что JTree поставляется с BasicTreeUI.MouseHandler, см. javax.swing.plaf.basic.BasicTreeUI.
чтобы ответить на центральный вопрос, "что запускает fireValueChanged", ответ "этот обработчик мыши"... который оказывается единственным слушателем мыши, возвращаемым при переходе к tree.getMouseListeners().
Поэтому вы должны заменить прослушиватель мыши по умолчанию своей версией... что немного сложнее. Я использую Jython, который должен открыть каждый. Однако этот код не должен быть слишком сложным для перевода на Java:
from javax.swing.plaf.basic import BasicTreeUI
def makeMouseHandlerClass():
class MouseHandlerClass( BasicTreeUI.MouseHandler ):
def mousePressed( self, mouseEvent ):
genLog.info( "mouse handler MOUSE PRESSED!" )
nTFSelf.mousePressedStatus = True
BasicTreeUI.MouseHandler.mousePressed( self, mouseEvent )
nTFSelf.mousePressedStatus = False
return MouseHandlerClass
suppliedMouseHandler = nTFSelf.taskTree.mouseListeners[ 0 ]
nTFSelf.taskTree.removeMouseListener( suppliedMouseHandler )
nTFSelf.taskTree.addMouseListener( makeMouseHandlerClass()( nTFSelf.taskTree.getUI() ))
... в основном эквивалентная Java здесь будет расширять BasicTreeUI.MouseHandler как MyMouseHandler, а затем в последней строке заменить на новый MyMouseHandler( tree.getUI())... "nTFSelf" здесь это просто ссылка на "this"объект кода, где все это пишется...