Раздельная обработка одиночного и двойного клика мыши в swing

Иногда возникает потребность в раздельной обработке одинарного и двойного клика. Например, у нас есть дерево, где каждый элемент содержит чекбокс. Мы хотим, чтобы поведение дерева было следующим: одинарный клик должен просто выделять элемент или снимать выделение, в то время как двойной клик должен обрабатываться стандартным для дерева образом.

На первый взгляд задача достаточно простая, можно сделать свой слушатель событий мыши и использовать метод getClickCount() класса MouseEvent . Однако при этом мы сталкиваемся с непреодолимой проблемой: при одинарном и двойном клике всегда будет вызываться метод mouseClicked(MouseEvent e) при том, что getClickCount() выдаст 1. Т.е. мы никак не можем сказать, в момент обработке события мыши с getClickCount() равным 1, будет ли потом вызов этого же события с getClickCount() равным 1.

Решить эту проблему можно с помощью javax.swing.Timer. Сперва несколько слов об этом классе. Этот класс служит для того, чтобы запустить одно или несколько действий после определенного интервала ожидания. Наиболее ценным свойством этого класса является то, что действия выполняются в основном потоке GUI или потоке обработки событий. Так, как класс запускает дополнительный поток, а мы работаем в потоке обработке событий, что накладывает некоторые особенности на реализацию многозадачности, нам не надо думать об этих особенностях. Т.е. нам не надо думать о специфике многозадачности в swing.

Ниже приведен код слушателя обработки событий мыши.

public class NodeMouseListener extends MouseAdapter {
        private
JTree tree;
        private
boolean singleClick = true;
        private
Timer timer;
        private
TreePath path = null;;
        private
int row = 0;
       
        private final
int delay = 170;

         
NodeMouseListener(JTree tree) {
this.tree = tree;
ActionListener al = new ActionListener(){
public
void actionPerformed(ActionEvent evt) {
if(
singleClick){
         
processSingleClick();
}
}
};
timer = new javax.swing.Timer(delay, al);
timer.setRepeats(false);
}

public
void mouseClicked(MouseEvent e) {
         
checkClicks(e);
}

private
void checkClicks(MouseEvent e){
         
int x = e.getX();
int y = e.getY();
int row = tree.getRowForLocation(x, y);
path = tree.getPathForRow(row);
if(
e.getClickCount() == 1){
         
singleClick = true;
         
timer.start();
}else{
         
singleClick = false;         
}
}

private
void processSingleClick(){         
         if(
path != null){
                
//обрабатываем одинарный клик здесь
         
}
}


}

Этот класс надо зарегистрировать в экземпляре класса дерева, как один из слушателей событий мыши.

Если подобрать delay, то можно добиться такого поведения дерева, как требуется в задаче.

Автор: Добрица Федор