Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

dynamica buttons in pyqt5



  • How can I handle each button separately? I want to create multiple of buttons based on the worker's names so I did a for loop based on the worker numbers I have on my DB so I have multiple of assign buttons and workers names as labels,when clicking the assign button I want to save the name of the worker in the, but it only save the last value whenever i clicked. connect to function
    here is my code in python :

    ## repeated for every worker
        for i in range(2):
    
            self.Vl_name_location = QtWidgets.QVBoxLayout()
            self.Vl_name_location.setObjectName("Vl_name_location")
            self.worker_name = QtWidgets.QLabel(self.groupBox)
            self.worker_name.setAlignment(QtCore.Qt.AlignCenter)
    
            ## from db
            self.worker_name.setText("worker_name")
            self.worker_name.setObjectName("worker_name")                       
            self.Vl_name_location.addWidget(self.worker_name)
            self.worker_location = QtWidgets.QLabel(self.groupBox)
            self.worker_location.setAlignment(QtCore.Qt.AlignCenter)
            self.worker_location.setObjectName("worker_location")
            # from db
            self.worker_location.setText("Eng,Zone B")
            self.Vl_name_location.addWidget(self.worker_location)
            self.Hl_worker.addLayout(self.Vl_name_location)
            #####
            ### assign button to connect the name of the worker to the image       on the db
            #####
    
            self.assign_button = QtWidgets.QPushButton(self.groupBox)
            self.assign_button.setMinimumSize(QtCore.QSize(50, 25))
              self.assign_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
            self.assign_button.setStyleSheet("")
            self.assign_button.setObjectName("assign_button")
            self.assign_button.setText( "Assign" )
            self.assign_button.clicked.connect(lambda: self.assign_button_clicked(self.worker_name.text() ))
            self.Hl_worker.addWidget(self.assign_button)
    

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    You are overwriting your buttons doing it like that. You should store a list of your buttons if you want to access them again.



  • @SGaist i tried to store all the buttons but still it only save the last value
    here is my code inside a for loop :

    
                self.assign_button = QtWidgets.QPushButton(self.groupBox)
                self.assign_button.setMinimumSize(QtCore.QSize(50, 25))
                self.assign_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
                self.assign_button.setStyleSheet("")
                self.assign_button.setObjectName("assign_button")
                self.assign_button.setText("Assign")
                btns.append(self.assign_button)
                btns[i].clicked.connect(lambda: self.assign_button_clicked(str(i), 1))
    

  • Lifetime Qt Champion

    You are still overwriting self.assign_button.



  • @sara12333
    As @SGaist says. If you are going to going to be creating all those widgets multiple times as per the the for loop, you''re going to want to make all these variables as arrays. So it's not just, say, self.assign_button that needs array-izing, but also, say, self.worker_name, and everything else.

    At least if you want to be able to reference them later on. At the moment what you are doing is creating multiple Qt widgets OK, but you are always storing them into some self.something variable, so that will only ever end up being a reference to the ones you created in the final pass through the loop.

    If you are really going to be creating multiple "groups" of widgets like this, you would probably be best defining a container class when holds (references to) each of the widgets it uses. Then you can create an array (Python list) of each container widget easily, and access widgets via the elements in that array. self.worker_group_of_widgets[i].assign_button, etc.



  • @JonB Thank you for your reply, I hope that I understood that since I'm new in python so here is my code depending on my understanding:

    class worker_group_of_widgets:
    
        def __init__(self,assign_button=None, groupBox=None,verticalLayout=None,Hl_worker=None,label_img=None,Vl_name_location=None,worker_name=None,worker_location=None):
            self.assign_button       = assign_button
            self.groubBox            = groupBox
            self.Vl_name_location    = Vl_name_location
            self.verticalLayout      = verticalLayout
            self.Hl_worker           = Hl_worker
            self.label_img           = label_img
            self.worker_name         = worker_name
            self.worker_location     = worker_location
    
    containter = []
            ##############
            ## repeated for every worker
            for i in range(2):
    
                containter[i] = worker_group_of_widgets()
                containter[i].groubBox=QtWidgets.QGroupBox(self.scrollAreaWidgetContents_2)
                   containter[i].assign_button = QtWidgets.QPushButton(containter[i].groubBox)
                containter[i].assign_button.clicked.connect(lambda: self.assign_button_clicked(str(i)))
    
    

    if the above code is correct i still got IndexError: list assignment index out of range


  • Qt Champions 2019

    @sara12333 said in dynamica buttons in pyqt5:

    IndexError: list assignment index out of range

    Of course - you do not append to the list.

    containter.append( worker_group_of_widgets())
    


  • @sara12333
    In addition to @jsulm's post.

    I'm not sure, but i think your new way omits some of the widget creation you had before you introduced the class-container?

    In any case, here is how I would do it. I am not going to write the whole thing for you, but I would have something like the following. Note that while I am at it I am making the class for this "user info" stuff its own QWidget. So:

    class WorkerInfo(QWidget):
      def __init__(self, parent: QWidget=None):
        super().__init__(parent)
    
        # here all/most of the stuff from your original loop
        self.Vl_name_location = QtWidgets.QVBoxLayout()
        ...
        self.assign_button = QtWidgets.QPushButton(self.groupBox)
        ...
    
    
    # now your loop in outside world, e.g. in your `QMainWindow`
    self.all_workers = []
    for i in range(2):
      worker = WorkerInfo(self)
      self.all_workers.push(worker)
      self.all_workers[i].assign_button.clicked.connect(lambda i: self.assign_button_clicked(str(i)))
    

    BTW, I think your current lambda: self.assign_button_clicked(str(i)) will not do as you intend. I think you will find that the i is always 1 (or even 2) when the slot is called, i.e. the value from the last iteration through your for loop. Note how I have passed i as a parameter to the lambda to avoid this. Mine is totally untested, you will have to do so! :)

    (I may have misunderstood where you want each assign_button = QtWidgets.QPushButton(self.groupBox) to appear, If that is not inside the "group-widget" you are creating for each worker then move it outside, as appropriate. Actually I may be wrong anyway, I think you do create them inside each worker group widget.)



  • Hi, I randomly came across this post, Wrote a quick script, Hope it helps

    Script :

    import sys
    from PyQt5 import QtWidgets
    from functools import partial
    
    
    class UI(QtWidgets.QMainWindow):
        def __init__(self):
            QtWidgets.QMainWindow.__init__(self)
            self.init_ui()
            self.populate_buttons()
    
        def init_ui(self):
            self.setFixedSize(300, 500)
            central_wid = QtWidgets.QWidget(self)
            self.setCentralWidget(central_wid)
            self.main_layout = QtWidgets.QVBoxLayout(self)
            central_wid.setLayout(self.main_layout)
    
        def populate_buttons(self):
            for i in range(10):
                a = AdvancedButton("Test Button", i)
                a.clicked.connect(partial(self.button_click_function, a.value))
                self.main_layout.addWidget(a)
    
        def button_click_function(self, _val):
            print("Button Value : ", _val)
    
    
    class AdvancedButton(QtWidgets.QPushButton):
        def __init__(self, button_name, value):
            QtWidgets.QPushButton.__init__(self, button_name)
            self.name = button_name
            self.value = value
    
    
    app = QtWidgets.QApplication(sys.argv)
    ex = UI()
    ex.show()
    sys.exit(app.exec_())
    

    UI and Output :
    c1b8e5e0-aa2b-4547-a4f3-b46c2422d205-image.png

    As already mentioned by another member, Depending on the need, you might want to store the buttons to a list./array

    ( replied as it's still listed as unsolved)

    Bharath


Log in to reply