Skip to content Skip to sidebar Skip to footer

Detecting Mechanical Button Press With Python3 And Qt5

I have an application that is developed in Python 5.3 and PyQt 7.1 (I think). So far I have everything in the GUI working just fine. I now need to be able to detect the pressing

Solution 1:

The error you are seeing is likely due to this issue. While you may not actually have it in a while loop like that question, chances are you are calling it multiple times because you've got it in a Qt callback or similar. Anyway...on to how to integrate it with Qt...

The GPIO.add_event_detect method takes a callback to be executed on a state change of the GPIO port. The code monitoring the GPIO runs in a separate thread, which means the callback is run in a separate thread. This poses some problems for integrating with Qt, as you need to make sure you do it in a thread safe way (if you do it wrong, you'll probably end up with an error like this).

A simple solution is to assume that Qt signals are thread safe when called from Python threads (which is what the GPIO library will be using). This is a bit of an open question as far as I'm aware, as technically they are documented as not being thread safe when used from Python threads, but typically I've found it to be OK. If you want to take the risk of your program crashing occasionally, then this is how you do it "simply"

I'll assume you have a subclass of QMainWindow in your program, but this will work added to any Qt class:

classMainWindow(QMainWindow):
    event_detected = pyqtSignal(int)
    def__init__(self, *args, **kwargs):
        QMainWindow.__init__(self, *args, **kwargs)

        self.event_detected.connect(self.on_gpio_event)
        GPIO.add_event_detect(channel, GPIO.BOTH, callback=self.event_detected.emit)

    defon_gpio_event(self, channel):
        # your code here!print("An event occurred on channel {}".format(channel))

Alternatively, doing it the "definitely safe" way involves slightly more work. Here you tell the GPIO library to place any events into a thread safe Python queue, which is thread read out by a QThread which emits the Qt signal (Qt signals are definitely thread safe when used from QThreads)

from six.moves.queue import Queue

classRelayThread(QThread):
    event_detected = pyqtSignal(int)
    def__init__(self, *args, **kwargs):
        QThread.__init__(self, *args, **kwargs)
        self.queue = Queue()
        GPIO.add_event_detect(channel, GPIO.BOTH, callback=self.queue.put)

    defrun(self):
        whileTrue:
            self.event_detected.emit(self.queue.get())

classMainWindow(QMainWindow):
    def__init__(self, *args, **kwargs):
        QMainWindow.__init__(self, *args, **kwargs)

        self.relay_thread = RelayThread()
        self.relay_thread.event_detected.connect(self.on_gpio_event)
        self.relay_thread.start()

    @pyqtSlot(int)defon_gpio_event(self, channel):
        # your code here!print("An event occurred on channel {}".format(channel))

Anyway, hope that helps. It's a bit hard to do any more without specific code from you, but in general, this is how you interface the GPIO ports on a raspberry pi with the Qt event loop.

Post a Comment for "Detecting Mechanical Button Press With Python3 And Qt5"