I used PyQt5 for a project and have the following snippet (button
is a QPushButton)
def on_receive(self, query):
print("receiving", query)
datapackages = json.loads(query)
for button, datapackage in zip(self.buttonArray, datapackages):
self.wire_up_button(datapackage, button)
def wire_up_button(self, datapackage, button):
title, songid = datapackage["title"], datapackage["songid"]
button.setText(title + " (" + str(datapackage["votes"]) + ")")
button.clicked.connect(lambda: self.upvote(songid))
def upvote(self, sid):
text = '{"action":"upvote", "value":"' + sid + '"}\n'
print(text)
self.send(text)
def send(self, text):
print("Sending")
The on_receive
function is connected to a soccet client and will be called wheneever a data package is received. The layout is a bit complicated because my UI has so many buttons it's handier to iterate over them than to hard-code every single one.
Whenever I click the button, the wire-up function wires the button to the upvote function, which creates a json protocl and sends it to the socket server. However, the wireup-function is called twice per click. (I am certain of this because of the debug print commands). There is no other call in the send function in my program.
I speculate that this might be due to how clicked.connect works (maybe it fires upon click and release).
I used the QtDesigner to create the UI and loaded the .uic
in my main.py
Every time you receive anything from socket you do
for button, datapackage in zip(self.buttonArray, datapackages):
self.wire_up_button(datapackage, button)
and in self.wire_up_button
you connect to button clicked event. Note, that self.buttonArray
is always the same list of buttons, so every time on_receive
is called you add 1 new subscription to each button click. But previous subscription to button click still exists, so on button click upvote
will be called multiple times with different sid
. You need to disconnect from button click event before adding new one:
def wire_up_button(self, datapackage, button):
try:
button.clicked.disconnect()
except:
pass
title, songid = datapackage["title"], datapackage["songid"]
button.setText(title + " (" + str(datapackage["votes"]) + ")")
button.clicked.connect(lambda: self.upvote(songid))
try ... except
block is required, because button.clicked.disconnect()
raises exception if no functions were connected to click event.