Distinguishing Single and Double Clicks on QListWidget in PyQt4

The problem

QListWidget exposes itemClicked and itemDoubleClicked, but triggering the double-click signal also fires the single-click slot. That is fine when the actions are unrelated, but not when the logic overlaps.

Solution

Qt does not provide a built-in fix, so we debounce the signals ourselves. A Stack Overflow answer suggests this C++ pattern:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void YourClass::itemClicked(QListWidgetItem* listWidgetItem) {
if (!mDoubleClicked) {
QTimer::singleShot(300, this, SLOT(itemClickedTimeout()));
mSingleClickedItem = listWidgetItem;
}
}

void YourClass::itemClickedTimeout() {
if (!mDoubleClicked) {
// do something, listitem has been clicked once
} else mDoubleClicked = false;
}

void YourClass::itemDoubleClicked(QListWidgetItem* listWidgetItem) {
mDoubleClicked = true;

// do something, listitem has been clicked twice
}

Translated into PyQt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Main(QtGui.QMainWindow):

def __init__():

self.is_double_clicked = False
self.listwidget.itemClicked.connect(self.item_clicked)
self.listwidget.itemDoubleClicked.connect(self.item_double_clicked)

.....................................

def item_clicked(self, item):
if not self.is_double_clicked:
QtCore.QTimer.singleShot(300, self.item_clicked_timeout)

def item_clicked_timeout(self):
if not self.is_double_clicked:
# do something when item clicked
pass
else:
self.is_double_clicked = False

def item_double_clicked(self):
self.is_double_clicked = True
# do something when item double clicked
pass

Reference:

QListWidget itemClicked and itemDoubleClicked - block single click if double click