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)
-
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))
-
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 thefor
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
-
@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 thei
is always1
(or even2
) when the slot is called, i.e. the value from the last iteration through yourfor
loop. Note how I have passedi
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 :
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