Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Language Bindings
  4. Two (probably) very simple questions
Forum Updated to NodeBB v4.3 + New Features

Two (probably) very simple questions

Scheduled Pinned Locked Moved Solved Language Bindings
pyqt
14 Posts 3 Posters 9.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Sorren
    wrote on last edited by A Former User
    #1

    I have never attempted to program a GUI before, and I am having some trouble. I am working on the Raspberry Pi, and I am trying to create a GUI with two facets: There is a button which turns on and off an LED, and there is a label which, based on a voltage drop across two resistors, tells the user whether the LED is, in fact, on or off.

    GPIO is set up and the readadc() function is defined elswhere in the code. This is what I have:

    @
    import sys
    from PyQt4 import QtCore, QtGui

    class Window(QtGui.QWidget):
    def init(self):
    super(Window, self).init()

    self.initUI()

    def initUI(self):
    button = QtGui.QPushButton('Toggle LED', self)
    button.setCheckable(True)
    button.move(145, 50)

    label = QtGui.QLabel(self)
    label.setText("initializing...")
    label.move(145, 25)

    button.clicked[bool].connect(self.toggleLED)
    self.checkLED()

    self.setGeometry(300,300,280,170)
    self.setWindowTitle('LED Interface')
    self.show()

    def toggleLED(self, pressed):
    source = self.button()
    if pressed:
    GPIO.output(22,1)
    else:
    GPIO.output(22,0)

    def checkLED(self):
    V1 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
    V2 = readadc(1, SPICLK, SPIMOSI, SPIMISO, SPICS)
    Vdrop = V1-V2
    LED_Status = (Vdrop > 350) and (Vdrop < 450)

    if LED_Status == True:
    text = "The LED is ON"
    else:
    text = "The LED is NOT ON"
    self.label.setText(text)

    def main():

    app = QtGui.QApplication(sys.argv)
    ex = Window()

    if name == 'main':
    main()@

    When I run this code, I get an error, reading:
    "AttributeError: 'Window' has no attribute 'Label'"
    specifically pertaining to the calling of
    @self.label.setText(text)@
    How can I fix this, so that the label changes?

    As a test, I commented out the line
    @self.checkLED()@
    to see what would happen. The result: Nothing. The code ran without any errors, but no window popped up and nothing happened. This is almost definitely due to my complete lack of knowledge in PyQt and Object Oriented Programming in general. What can I do to make the UI actually manifest?

    Also, is there anything else glaringly wrong with this code?

    1 Reply Last reply
    0
    • jazzycamelJ Offline
      jazzycamelJ Offline
      jazzycamel
      wrote on last edited by
      #4

      You are absolutely correct, your checkLED() function is only called once when the Window() is created. The following example uses a QTimer that calls your checkLED method once a second:

      @
      from PyQt4 import QtCore, QtGui

      class Window(QtGui.QWidget):
      def init(self):
      super(Window, self).init()

          self.initUI()
      
      def initUI(self):
          l=QtGui.QVBoxLayout(self)
      
          button = QtGui.QPushButton('Toggle LED', self)
          button.setCheckable(True)
          l.addWidget(button)
      
          self.label = QtGui.QLabel(self)
          self.label.setText("initializing...")
          l.addWidget(self.label)
      
          button.clicked[bool].connect(self.toggleLED)
          
          self.timer=QtCore.QTimer(self)
          self.timer.timeout.connect(self.checkLED)
          self.timer.start(1000)
      
          self.setWindowTitle('LED Interface')
          self.show()
      
      def toggleLED(self, pressed):
          if pressed: GPIO.output(22,1)
          else: GPIO.output(22,0)
      
      @QtCore.pyqtSlot()
      def checkLED(self):
          V1 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
          V2 = readadc(1, SPICLK, SPIMOSI, SPIMISO, SPICS)
          Vdrop = V1-V2
          LED_Status = (Vdrop > 350) and (Vdrop < 450)
      
          if LED_Status: text = "The LED is ON"
          else: text = "The LED is NOT ON"
          self.label.setText(text)
      

      if name == 'main':
      from sys import argv, exit

      app = QtGui.QApplication(argv)
      ex = Window()
      ex.show()
      exit(app.exec_())
      

      @

      Hope this helps ;o)

      For the avoidance of doubt:

      1. All my code samples (C++ or Python) are tested before posting
      2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
      1 Reply Last reply
      0
      • jazzycamelJ Offline
        jazzycamelJ Offline
        jazzycamel
        wrote on last edited by
        #2

        Hi Sorren, welcome to Qt!

        Glad to see someone else using PyQt on Raspberry Pi ;o) I've gone through and amended your code listing as follows:

        @
        from PyQt4 import QtCore, QtGui

        class Window(QtGui.QWidget):
        def init(self):
        super(Window, self).init()

            self.initUI()
        
        def initUI(self):
            button = QtGui.QPushButton('Toggle LED', self)
            button.setCheckable(True)
            button.move(145, 50)
        
            self.label = QtGui.QLabel(self)
            self.label.setText("initializing...")
            self.label.move(145, 25)
        
            button.clicked[bool].connect(self.toggleLED)
            self.checkLED()
        
            self.setGeometry(300,300,280,170)
            self.setWindowTitle('LED Interface')
            self.show()
        
        def toggleLED(self, pressed):
            if pressed: GPIO.output(22,1)
            else: GPIO.output(22,0)
        
        def checkLED(self):
            V1 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
            V2 = readadc(1, SPICLK, SPIMOSI, SPIMISO, SPICS)
            Vdrop = V1-V2
            LED_Status = (Vdrop > 350) and (Vdrop < 450)
        
            if LED_Status: text = "The LED is ON"
            else: text = "The LED is NOT ON"
            self.label.setText(text)
        

        if name == 'main':
        from sys import argv, exit

        app = QtGui.QApplication(argv)
        ex = Window()
        ex.show()
        exit(app.exec_())
        

        @

        There were a few fundamental issues here to address:

        Python code should be indented consistently with exactly 4 spaces (not tabs!)

        Your label has to belong to the instance (self) of the Window() that you are creating to be able to reference it (see line 14, self.label)

        The reason you couldn't see your window (even with the errors commented out) is because you a) hadn't called show() on your window and, b) becuase you hadn't started an event loop (app.exec_()).

        These are just a few fundamental things to do with Python, OO and Qt: once learned never forgotten ;o) There are some really good tutorials out there that will explain these things.

        Hope this gets you up and running and good luck and feel free to ask more questions ;o)

        For the avoidance of doubt:

        1. All my code samples (C++ or Python) are tested before posting
        2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
        1 Reply Last reply
        0
        • S Offline
          S Offline
          Sorren
          wrote on last edited by
          #3

          Thank you so much for your help! I implemented the changes you suggested, and now the window pops up, and pressing the button results the LED turning on or off. However, the label stays the same, reading that the LED is off the whole time. Assuming that my function for checking the LED is correct, is it possible that the function is only called once, at the beginning? Is there a way in which I could call it constantly throughout the program without changing the button's ability to toggle the light?

          1 Reply Last reply
          0
          • jazzycamelJ Offline
            jazzycamelJ Offline
            jazzycamel
            wrote on last edited by
            #4

            You are absolutely correct, your checkLED() function is only called once when the Window() is created. The following example uses a QTimer that calls your checkLED method once a second:

            @
            from PyQt4 import QtCore, QtGui

            class Window(QtGui.QWidget):
            def init(self):
            super(Window, self).init()

                self.initUI()
            
            def initUI(self):
                l=QtGui.QVBoxLayout(self)
            
                button = QtGui.QPushButton('Toggle LED', self)
                button.setCheckable(True)
                l.addWidget(button)
            
                self.label = QtGui.QLabel(self)
                self.label.setText("initializing...")
                l.addWidget(self.label)
            
                button.clicked[bool].connect(self.toggleLED)
                
                self.timer=QtCore.QTimer(self)
                self.timer.timeout.connect(self.checkLED)
                self.timer.start(1000)
            
                self.setWindowTitle('LED Interface')
                self.show()
            
            def toggleLED(self, pressed):
                if pressed: GPIO.output(22,1)
                else: GPIO.output(22,0)
            
            @QtCore.pyqtSlot()
            def checkLED(self):
                V1 = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS)
                V2 = readadc(1, SPICLK, SPIMOSI, SPIMISO, SPICS)
                Vdrop = V1-V2
                LED_Status = (Vdrop > 350) and (Vdrop < 450)
            
                if LED_Status: text = "The LED is ON"
                else: text = "The LED is NOT ON"
                self.label.setText(text)
            

            if name == 'main':
            from sys import argv, exit

            app = QtGui.QApplication(argv)
            ex = Window()
            ex.show()
            exit(app.exec_())
            

            @

            Hope this helps ;o)

            For the avoidance of doubt:

            1. All my code samples (C++ or Python) are tested before posting
            2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
            1 Reply Last reply
            0
            • S Offline
              S Offline
              Sorren
              wrote on last edited by
              #5

              Thanks, everything works now.

              1 Reply Last reply
              0
              • S Offline
                S Offline
                Stumbino
                wrote on last edited by
                #6

                Has anyone gotten a button to click for the pyqt gui? This is a GPIO Output signaling button is clicked. Does anyone have a solution to this?

                jazzycamelJ 1 Reply Last reply
                0
                • S Stumbino

                  Has anyone gotten a button to click for the pyqt gui? This is a GPIO Output signaling button is clicked. Does anyone have a solution to this?

                  jazzycamelJ Offline
                  jazzycamelJ Offline
                  jazzycamel
                  wrote on last edited by
                  #7

                  @Stumbino
                  Not sure that I understand your question: do you mean you want a Qt signal to be emitted when a a GPIO input is changed/toggled?

                  For the avoidance of doubt:

                  1. All my code samples (C++ or Python) are tested before posting
                  2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
                  S 1 Reply Last reply
                  0
                  • jazzycamelJ jazzycamel

                    @Stumbino
                    Not sure that I understand your question: do you mean you want a Qt signal to be emitted when a a GPIO input is changed/toggled?

                    S Offline
                    S Offline
                    Stumbino
                    wrote on last edited by
                    #8

                    @jazzycamel Most of the resources online are only discussing pyqt and gpio output(ex: turning a lightbulb on). Has anyone gotten pyqt to work as a GPIO button signalling the computer that the button is pressed as a GPIO input (sorry messed that up previously)? The only information that I have found so far is making a thread (qthread) so looping can be processed separately, but I have not seen an example of this working for GPIO input . An example would be greatly appreciated! Thanks!

                    1 Reply Last reply
                    0
                    • jazzycamelJ Offline
                      jazzycamelJ Offline
                      jazzycamel
                      wrote on last edited by
                      #9

                      @Stumbino

                      Something like the following should do what you want (if I'm understanding you correctly):

                      import RPi.GPIO as GPIO
                      GPIO.setmode(GPIO.BCM)
                      
                      from functools import partial
                      from PyQt5.QtCore import QObject, pyqtSignal
                      pyqtWrapperType=type(QObject)
                      
                      class Singleton(pyqtWrapperType):
                          _instances={}
                          def __call__(cls, *args, **kwargs):
                              if cls not in cls._instances:
                                  cls._instances[cls]=super(Singleton, cls).__call__(*args, **kwargs)
                              return cls._instances[cls]
                      
                      class QGPIO(QObject, metaclass=Singleton):
                          interrupted=pyqtSignal(int,int)
                      
                          @staticmethod
                          def _callback(pin, event):
                              QGPIO().interrupted.emit(pin,event)
                      
                          def register(self, pin, event, bounceTime=300):
                              callback=partial(self._callback, pin, event)
                              GPIO.add_event_detect(pin, event, callback=callback, bouncetime=bounceTime)
                      
                      if __name__=="__main__":
                          from sys import argv, exit
                          from PyQt5.QtCore import pyqtSlot
                          from PyQt5.QtWidgets import QApplication, QWidget
                      
                          class Widget(QWidget):
                              def __init__(self, parent=None, **kwargs):
                                  super().__init__(parent, **kwargs)
                      
                                  GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
                      
                                  QGPIO().interrupted.connect(self.interrupted)
                                  QGPIO().register(17, GPIO.FALLING)
                      
                              @pyqtSlot(int,int)
                              def interrupted(self, pin, event):
                                  print("Interrupted:", pin, event)
                      
                          a=QApplication(argv)
                          w=Widget()
                          w.show()
                          exit(a.exec_())
                      

                      Basically(!), I create a singleton QObject() that has a callback that can be registered with the RPi.GPIO interrupt system such that, when an edge change is detected, the QGPIO() class will trap the interrupt via _callback and then emit a signal interrupted(int,int) which will inform a slot of which pin has changed and by which event type.

                      Just a warning/disclaimer: I've tested all the PyQt bits, but I had to stub the RPi.GPIO bits as I don't have a Pi handy right this second.

                      For the avoidance of doubt:

                      1. All my code samples (C++ or Python) are tested before posting
                      2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
                      1 Reply Last reply
                      1
                      • S Offline
                        S Offline
                        Stumbino
                        wrote on last edited by
                        #10

                        @jazzycamel What do I change to make this work for pyqt4? I am currently using a RaspberryPi 0 and it looks like pyqt5 doesnt have full support for arm v6 cpu.

                        jazzycamelJ 1 Reply Last reply
                        0
                        • S Stumbino

                          @jazzycamel What do I change to make this work for pyqt4? I am currently using a RaspberryPi 0 and it looks like pyqt5 doesnt have full support for arm v6 cpu.

                          jazzycamelJ Offline
                          jazzycamelJ Offline
                          jazzycamel
                          wrote on last edited by
                          #11

                          @Stumbino
                          Not much I shouldn't have thought...

                          Change the PyQt5 imports to PyQt4 and use the Python 2 (I'm assuming you are using Python 2 with PyQt4?) metaclass syntax i.e.:

                          class QGPIO(QObject):
                              __metaclass__=Singleton
                          

                          Should work fine. I don't have a PyQt4 setup to test I am afraid, but if you have any issues just post 'em here :)

                          For the avoidance of doubt:

                          1. All my code samples (C++ or Python) are tested before posting
                          2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
                          1 Reply Last reply
                          1
                          • S Offline
                            S Offline
                            Stumbino
                            wrote on last edited by
                            #12

                            @jazzycamel I got all the libraries switched over to pyqt4, but I get these two errors when I run the program.0_1513063657608_main.png

                            jazzycamelJ 1 Reply Last reply
                            0
                            • S Stumbino

                              @jazzycamel I got all the libraries switched over to pyqt4, but I get these two errors when I run the program.0_1513063657608_main.png

                              jazzycamelJ Offline
                              jazzycamelJ Offline
                              jazzycamel
                              wrote on last edited by jazzycamel
                              #13

                              @Stumbino Replace the line containing super. __init__ with:

                              QWidget.__init__(self, parent, **kwargs)
                              

                              For the avoidance of doubt:

                              1. All my code samples (C++ or Python) are tested before posting
                              2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
                              1 Reply Last reply
                              0
                              • S Offline
                                S Offline
                                Stumbino
                                wrote on last edited by
                                #14

                                @jazzycamel That worked! How would I load a UI file in the Widget class? I tried using uic.loadUI(), but that seems to override the previous gui.

                                1 Reply Last reply
                                0

                                • Login

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved