Hi,
Is there I can batch create and connect button widgets?
My main usage is
- List a scripts of a directory
- Create buttons based on those scripts
- Connect the buttons where if a button is clicked the corresponding script is executed.
I can manage #1 and #2 but not #3.
In C4D, this was easy since every button creation needs a unique ID. So I just need to mapped the unique ID to a script/command.
In PySide2 Maya, I can’t attached a unique ID to the button. I also can’t create a variable for every button since there are a lot and it would be hard to maintain.
Is there a way around this?
Here is a snippet of the working code:
# Assume these are the list of scripts with the corresponding commands from #1
general_cmds = [
("Hello Universe", {"id": 111120, "cmds": 'util.universe.main()'} ),
("Hello World", {"id": 111130, "cmds": 'util.print_world.main()'} ),
("Hello Milkyway", {"id": 111140, "cmds": 'util.print_milyway.main()'} ),
]
button_layout = QtWidgets.QHBoxLayout()
button_layout.addStretch(3)
self.command = None
for command in general_cmds:
self.command = command
btn = QtWidgets.QPushButton(command[0])
button_layout.addWidget(btn)
btn.clicked.connect(self.btn_command)
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.addLayout(button_layout)
# This is my problem
# The function works but it is stuck with latest self.command loop.
# So even if I press "Hello Universe" or "Hello World", its always the "Hello Milkway" command that is executed.
def btn_command(self):
eval (self.command[1]['cmds'])
You’re looping over general_cmds
, and every loop setting self.command = command
. That means that the last time through the loop, self.command
is set to “Hello Milkyway”. So when the loop is done and you get down to btn_command
it will only ever be the last item in the list: “Hello Milkyway”.
And there’s no reason to have btn_command
. You can just connect the button directly to the function you want called. That also means you don’t need the ID at all.
button_layout = QtWidgets.QHBoxLayout()
button_layout.addStretch(3)
general_cmds = [
("Hello Universe", "util.universe.main"),
("Hello World", "util.print_world.main"),
("Hello Milkyway", "util.print_milyway.main"),
]
for cmd_text, cmd_func in general_cmds:
btn = QtWidgets.QPushButton(cmd_text)
button_layout.addWidget(btn)
btn.clicked.connect(eval(cmd_func))
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.addLayout(button_layout)
1 Like
Ah gotcha.
Thanks for the help. Never though binding the clicked.connect
directly to the function rather than creating one.
Just an alternative, went to a rabbit hole and found that sender()
can also do the job but of course, your code is much more elegant 
For reference, here is the code solution for the sender()
route.
self.general_cmds = {"Hello Universe" : {"id": 111121, "cmds": 'util.universe.main()'},
"Hello World": {"id": 111121, "cmds": 'util.print_world.main()'} }
for key, value in self.general_cmds.items():
#self.command = command
btn = QtWidgets.QPushButton(key)
button_layout.addWidget(btn)
btn.clicked.connect(self.general_command)
def general_command(self):
sender = self.sender()
key = sender.text()
eval (self.general_cmds[key]["cmds"])