I'm making a simple GUI with Tkinter to subscribe and receive messages from an mqtt broker. I'm writing it myself because of some message decompressing issues, shouldn't matter. The thing is that when I connect and subscribe to a topic the client needs to stay running so I run it in a thread to avoid freezing the GUI. But because the thread stays running I can't rerun the subscribe action.
In the following way it works fine if you try once (please note that it is originally in an class, but I'm trying to only post the relevant methods):
def main_window(self):
self.root.title("MQTT Subscriber Test")
self.root.geometry("350x150")
# Topic subscription
title = tk.Label(self.root, text="Enter topic to subscribe:")
title.pack(**self.padding, anchor=tk.W)
topic_entry = tk.Entry(self.root, textvariable=self.topic)
self.root.update()
topic_entry.pack(**self.padding, **self.ipadding, anchor=tk.W, fill=tk.X)
# subscribe button
subscribe_button = tk.Button(self.root, text="Connect",
command=threading.Thread(target=self.subscribe_to_topic).start)
subscribe_button.pack(**self.padding, anchor=tk.W)
def subscribe_to_topic(self):
# ToDo: better condition for unsubscribe action
if self.subbed_topic != "":
self.client.unsubscribe_from_topic(self.subbed_topic)
self.client.disconnect_from_broker()
self.subbed_topic = self.get_topic
self.open_output_window()
self.client.operate(self.subbed_topic)
main_window()
sets up the interface and subscribe_to_topic()
is called when the subscribe button is pressed.
This runs fine once, but I can't re-press the button I get the error:
RuntimeError: threads can only be started once
So I tried switching the startup of the thread to the method itself like this:
def main_window(self):
self.root.title("MQTT Subscriber Test")
self.root.geometry("350x150")
# Topic subscription
title = tk.Label(self.root, text="Enter topic to subscribe:")
title.pack(**self.padding, anchor=tk.W)
topic_entry = tk.Entry(self.root, textvariable=self.topic)
self.root.update()
topic_entry.pack(**self.padding, **self.ipadding, anchor=tk.W, fill=tk.X)
# subscribe button
subscribe_button = tk.Button(self.root, text="Connect",
command=self.subscribe_to_topic))
subscribe_button.pack(**self.padding, anchor=tk.W)
def subscribe_to_topic(self):
# ToDo: better condition for unsubscribe action
if self.subbed_topic != "":
self.client.unsubscribe_from_topic(self.subbed_topic)
self.client.disconnect_from_broker()
self.subbed_topic = self.get_topic
self.open_output_window()
threading.Thread(target=self.client.operate(self.subbed_topic).start()
But that freezes the GUI again. From this point I couldn't find any other threads that solved my problem.
One thing that I noticed is that you are calling the function instead of passing the function to the thread.
In this case, the function is being called target=self.client.operate(self.subbed_topic)
and not being passed to the thread
Try refactoring the last line like this, and trying again?
threading.Thread(target=self.client.operate, args=(self.subbed_topic,)).start()