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

Dynamic grid with pushbuttons

Scheduled Pinned Locked Moved Solved Qt for Python
4 Posts 2 Posters 890 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 last edited by Sebastian Egger
    #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!

    JonBJ 1 Reply Last reply
    1
    • S Sebastian Egger

      @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!

      JonBJ Online
      JonBJ Online
      JonB
      wrote on last edited by JonB
      #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

        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!

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by JonB
        #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 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!

          JonBJ 1 Reply Last reply
          2
          • S Sebastian Egger

            @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!

            JonBJ Online
            JonBJ Online
            JonB
            wrote on last edited by JonB
            #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

            • Login

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