honeymoon
honeymoon

Reputation: 2520

Pyqt Mouse MouseButtonDblClick event

I have some trouble to distinguish between a single and a double mouse click event. I have created an event filter but a mouse double click also gives me a single signal back. In my code I have to separate both events to connect to different functions. Can anybody suggest me how to do this?

Here is an example. What I want is, if a double mouse click happen, only the MouseButtonDblClick should give a signal and not the LeftButton and MouseButtonDblClick:

    # coding: utf-8
    import sys

    from PyQt4 import QtCore, QtGui


    class MyDialog(QtGui.QDialog):
        def __init__(self, parent=None):
            super(MyDialog, self).__init__(parent)

            self.button1 = QtGui.QPushButton("Button 1")
            self.button2 = QtGui.QPushButton("Button 2")

            hbox = QtGui.QHBoxLayout()
            hbox.addWidget(self.button1)
            hbox.addWidget(self.button2)
            self.setLayout(hbox)

            self.button1.installEventFilter(self)

        def eventFilter(self, obj, event):

            if event.type() == QtCore.QEvent.MouseButtonPress:
                if event.button() == QtCore.Qt.LeftButton:
                    #If image is left clicked, display a red bar.
                    print 'one left'
                elif event.button() == QtCore.Qt.RightButton:
                    print 'one right'
            elif event.type() == QtCore.QEvent.MouseButtonDblClick:
                #If image is double clicked, remove bar.
                print 'two'

            return super(MyDialog, self).eventFilter(obj, event)


    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        w = MyDialog()
        w.show()
        sys.exit(app.exec_())

Thank you in advance!

Stefanie

Upvotes: 2

Views: 16023

Answers (2)

Vincent
Vincent

Reputation: 13415

It's kind of a hack, but it should do the trick. Also, I used new-style signals instead of your event filter, something you should consider. Here, the ClickHandler class counts the number of clicks between the first click and the timeout event of its timer.

from PyQt4 import QtCore, QtGui

class ClickHandler():
    def __init__(self, time):
        self.timer = QtCore.QTimer()
        self.timer.setInterval(time)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.timeout)
        self.click_count = 0

    def timeout(self):
        if self.click_count == 1:
            print('Single click')
        elif self.click_count > 1:
            print('Double click')    
        self.click_count = 0

    def __call__(self):
        self.click_count += 1
        if not self.timer.isActive():
            self.timer.start()


class MyDialog(QtGui.QDialog):
    def __init__(self, parent=None):
        super(MyDialog, self).__init__(parent)

        self.button1 = QtGui.QPushButton("Button 1")
        hbox = QtGui.QHBoxLayout()
        hbox.addWidget(self.button1)
        self.setLayout(hbox)

        self.click_handler = ClickHandler(300)
        self.button1.clicked.connect(self.click_handler)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    w = MyDialog()
    w.show()
    sys.exit(app.exec_())

EDIT : A second cleaner version with a CustomButton class that handles left and right click signals:

from PyQt4 import QtCore, QtGui

class CustomButton(QtGui.QPushButton):

    left_clicked= QtCore.pyqtSignal(int)
    right_clicked = QtCore.pyqtSignal(int)

    def __init__(self, *args, **kwargs):
        QtGui.QPushButton.__init__(self, *args, **kwargs)
        self.timer = QtCore.QTimer()
        self.timer.setInterval(250)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.timeout)
        self.left_click_count = self.right_click_count = 0

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.left_click_count += 1
            if not self.timer.isActive():
                self.timer.start()
        if event.button() == QtCore.Qt.RightButton:
            self.right_click_count += 1
            if not self.timer.isActive():
                self.timer.start()

    def timeout(self):
        if self.left_click_count >= self.right_click_count:
            self.left_clicked.emit(self.left_click_count)
        else:
            self.right_clicked.emit(self.right_click_count)
        self.left_click_count = self.right_click_count = 0


class MyDialog(QtGui.QDialog):
    def __init__(self, parent=None):
        super(MyDialog, self).__init__(parent)
        self.button1 = CustomButton("Button 1")
        hbox = QtGui.QHBoxLayout()
        hbox.addWidget(self.button1)
        self.setLayout(hbox)
        self.button1.left_clicked[int].connect(self.left_click)
        self.button1.right_clicked[int].connect(self.right_click)

    def left_click(self, nb):
        if nb == 1: print('Single left click')
        else: print('Double left click')

    def right_click(self, nb):
        if nb == 1: print('Single right click')
        else: print('Double right click')


if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    w = MyDialog()
    w.show()
    sys.exit(app.exec_())

Upvotes: 5

You should have a look at this thread on Double-Click-Capturing.

A Timer might do the job. However, it is probably a bad idea to have unrelated single clicks and double clicks (see Bill's answer to "Distinguish between single and double click events in Qt").

Upvotes: 2

Related Questions