Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Dynamic grid with pushbuttons
Forum Updated to NodeBB v4.3 + New Features

Dynamic grid with pushbuttons

Scheduled Pinned Locked Moved Solved Qt for Python
4 Posts 2 Posters 494 Views
  • 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
    Sebastian Egger
    wrote on 7 Aug 2021, 07:06 last edited by Sebastian Egger 8 Jul 2021, 07:08
    #1

    Hi all,

    I would like to create a dynamic grid (i.e. with a dynamic size say n) of pushbuttons on a grid. When I click on the button a gridpoint-specific event should occur let's say the name of the button shall be displayed. Here is my code:

    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    import sys
    from PyQt5.QtWidgets import *
    from os import environ

    def suppress_qt_warnings():
    environ["QT_DEVICE_PIXEL_RATIO"] = "0"
    environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
    environ["QT_SCREEN_SCALE_FACTORS"] = "1"
    environ["QT_SCALE_FACTOR"] = "1"

    if name == "main":
    suppress_qt_warnings()

    class MainWindow(QMainWindow):

    def __init__(self,n):
        super().__init__()
        self.initUI(n)
    
    def initUI(self, n):
        self.lengthDF = n
        self.widthDF = n
        self.scroll = QScrollArea()
        self.widget = QWidget()
        self.grid = QGridLayout()
        self.grid.setVerticalSpacing(0)
        self.grid.setHorizontalSpacing(0)
    
        for i in range(0, self.widthDF):
            for j in range(0, self.lengthDF):
                    button = QPushButton()
                    button.setText(str(i)+","+str(j))
                    button.clicked.connect(lambda: self.clickme(str(button.text())))
                    self.grid.addWidget(button, j, i)
    
        self.widget.setLayout(self.grid)
        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scroll.setWidgetResizable(True)
        self.scroll.setWidget(self.widget)
        self.setCentralWidget(self.scroll)
        self.setGeometry(100, 100, 600, 500)
        self.setWindowTitle('TestGrid')
        self.show()
        return
    
    def clickme(self, text):
        print(text)
    

    def main(n = 5):
    app = QApplication(sys.argv)
    main = MainWindow(n)
    sys.exit(app.exec_())

    main()

    However, when I click a button always the text of the button (4,4) is displayed. Does anybody know how to fix that problem?

    Regards!

    J 1 Reply Last reply 7 Aug 2021, 09:33
    1
    • S Sebastian Egger
      7 Aug 2021, 10:53

      @JonB said in Dynamic grid with pushbuttons:

      changing-variable-in-the-loop

      Thanks a lot, JonB,

      That was the essential step! Only one thing: I had to use (notice the dummy variable state)

      button.clicked.connect(lambda state, btn = button: self.clickme(btn.text()))

      otherwise I get an error

      AttributeError: 'bool' object has no attribute 'text'

      there is a link to this problem

      https://stackoverflow.com/questions/35819538/using-lambda-expression-to-connect-slots-in-pyqt

      I guess what the problem is but at the moment my knowledge about lambdas is too restrictive to see it clearly...

      Thanks again for your help!

      J Offline
      J Offline
      JonB
      wrote on 7 Aug 2021, 11:29 last edited by JonB 8 Jul 2021, 11:43
      #4

      @Sebastian-Egger
      Yes, well done for adding the first parameter. I hadn't noticed that the QPushButton.clicked signal (e.g. https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QAbstractButton.html#PySide2.QtWidgets.PySide2.QtWidgets.QAbstractButton.clicked) passes checked as a parameter. Any extra named arguments must come after all unnamed arguments are specified, so if you need to add a named argument you need to pass any/all the existing, non-named arguments too.

      1 Reply Last reply
      0
      • S Sebastian Egger
        7 Aug 2021, 07:06

        Hi all,

        I would like to create a dynamic grid (i.e. with a dynamic size say n) of pushbuttons on a grid. When I click on the button a gridpoint-specific event should occur let's say the name of the button shall be displayed. Here is my code:

        from PyQt5.QtCore import *
        from PyQt5.QtGui import *
        import sys
        from PyQt5.QtWidgets import *
        from os import environ

        def suppress_qt_warnings():
        environ["QT_DEVICE_PIXEL_RATIO"] = "0"
        environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
        environ["QT_SCREEN_SCALE_FACTORS"] = "1"
        environ["QT_SCALE_FACTOR"] = "1"

        if name == "main":
        suppress_qt_warnings()

        class MainWindow(QMainWindow):

        def __init__(self,n):
            super().__init__()
            self.initUI(n)
        
        def initUI(self, n):
            self.lengthDF = n
            self.widthDF = n
            self.scroll = QScrollArea()
            self.widget = QWidget()
            self.grid = QGridLayout()
            self.grid.setVerticalSpacing(0)
            self.grid.setHorizontalSpacing(0)
        
            for i in range(0, self.widthDF):
                for j in range(0, self.lengthDF):
                        button = QPushButton()
                        button.setText(str(i)+","+str(j))
                        button.clicked.connect(lambda: self.clickme(str(button.text())))
                        self.grid.addWidget(button, j, i)
        
            self.widget.setLayout(self.grid)
            self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
            self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
            self.scroll.setWidgetResizable(True)
            self.scroll.setWidget(self.widget)
            self.setCentralWidget(self.scroll)
            self.setGeometry(100, 100, 600, 500)
            self.setWindowTitle('TestGrid')
            self.show()
            return
        
        def clickme(self, text):
            print(text)
        

        def main(n = 5):
        app = QApplication(sys.argv)
        main = MainWindow(n)
        sys.exit(app.exec_())

        main()

        However, when I click a button always the text of the button (4,4) is displayed. Does anybody know how to fix that problem?

        Regards!

        J Offline
        J Offline
        JonB
        wrote on 7 Aug 2021, 09:33 last edited by JonB 8 Jul 2021, 10:33
        #2

        @Sebastian-Egger said in Dynamic grid with pushbuttons:

        button.clicked.connect(lambda: self.clickme(str(button.text())))

        Hi and welcome.

        I don't know how you are supposed to know this, but as I discovered long ago Python lambda parameters in a loop don't work like you'd think they do! This ends up connecting each button with a lambda using button.text() in its body where button is always the value it had the last time through the loop, not its value at the time each button.clicked.connect() was executed.

        You have to pass a changing-variable-in-the-loop via a named parameter to the lambda [I remove the str() as unnecessary]:

        button.clicked.connect(lambda btn=button: self.clickme(btn.text()))
        

        Trust me! ;-)

        1 Reply Last reply
        3
        • S Offline
          S Offline
          Sebastian Egger
          wrote on 7 Aug 2021, 10:53 last edited by
          #3

          @JonB said in Dynamic grid with pushbuttons:

          changing-variable-in-the-loop

          Thanks a lot, JonB,

          That was the essential step! Only one thing: I had to use (notice the dummy variable state)

          button.clicked.connect(lambda state, btn = button: self.clickme(btn.text()))

          otherwise I get an error

          AttributeError: 'bool' object has no attribute 'text'

          there is a link to this problem

          https://stackoverflow.com/questions/35819538/using-lambda-expression-to-connect-slots-in-pyqt

          I guess what the problem is but at the moment my knowledge about lambdas is too restrictive to see it clearly...

          Thanks again for your help!

          J 1 Reply Last reply 7 Aug 2021, 11:29
          2
          • S Sebastian Egger
            7 Aug 2021, 10:53

            @JonB said in Dynamic grid with pushbuttons:

            changing-variable-in-the-loop

            Thanks a lot, JonB,

            That was the essential step! Only one thing: I had to use (notice the dummy variable state)

            button.clicked.connect(lambda state, btn = button: self.clickme(btn.text()))

            otherwise I get an error

            AttributeError: 'bool' object has no attribute 'text'

            there is a link to this problem

            https://stackoverflow.com/questions/35819538/using-lambda-expression-to-connect-slots-in-pyqt

            I guess what the problem is but at the moment my knowledge about lambdas is too restrictive to see it clearly...

            Thanks again for your help!

            J Offline
            J Offline
            JonB
            wrote on 7 Aug 2021, 11:29 last edited by JonB 8 Jul 2021, 11:43
            #4

            @Sebastian-Egger
            Yes, well done for adding the first parameter. I hadn't noticed that the QPushButton.clicked signal (e.g. https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QAbstractButton.html#PySide2.QtWidgets.PySide2.QtWidgets.QAbstractButton.clicked) passes checked as a parameter. Any extra named arguments must come after all unnamed arguments are specified, so if you need to add a named argument you need to pass any/all the existing, non-named arguments too.

            1 Reply Last reply
            0

            1/4

            7 Aug 2021, 07:06

            • Login

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