首页 > 解决方案 > Tkinter GUI 和 Signal.py - ValueError:信号仅在主线程中有效

问题描述

今天是个好日子

我目前正在尝试使用 Python 中的 MQTT 将 IoT 通信集成到KAAIoT,该 Python 发送从电机驱动器的保持寄存器读取的数据。该脚本在带有 Tkinter GUI 的 Raspberry pi 上运行以进行一些控制,但现在我想通过 IoT 接口监视和控制一些事情。

我测试了此处提供的示例脚本,并设法发送和接收一些垃圾数据,酷豆,但在尝试将其集成到应用程序时出现问题。

尝试 1:实现到主类中的代码。
结果:已建立连接,但由于主循环中的循环,GUI 未加载

代码示例在这里

尝试 2:在线程中运行“主”代码。
结果:错误

文件“/usr/lib/python3.7/signal.py”,第 47 行,信号处理程序 = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler)) ValueError: signal only works in main thread <---- ----

因此,如果我理解正确,信号模块需要 Tkinter 用于显示 GUI 的主线程,但如果它使用它,它会抑制 GUI。主线程的使用也在Signals and Threads 下进行了说明。

问题:是否可以以某种方式同时集成 GUI 和 MQTT?任何修复或工作替代方案将不胜感激。

标签: pythontkintersignalsmqtt

解决方案


您可以在单独的函数中移动 MQTT 内容并使用线程来执行此函数:

import threading
...

class MainView(tk.Frame):
    def __init__(self,  *args, **kwargs):
        ...
        clock()
        
        self.listener = SignalListener()
        threading.Thread(target=self.client_task, daemon=True).start()

    def client_task(self):        
        client = mqtt.Client(client_id=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)))

        data_collection_client = DataCollectionClient(client)
        data_collection_client.connect_to_server()

        client.on_message = on_message

        # Start the loop
        client.loop_start()

        fuelLevel, minTemp, maxTemp = 100, 95, 100

        # Send data samples in loop
        while self.listener.keepRunning:
            payload = data_collection_client.compose_data_sample(fuelLevel, minTemp, maxTemp)
            result = data_collection_client.client.publish(topic=data_collection_client.data_collection_topic, payload=payload)
            if result.rc != 0:
                print('Server connection lost, attempting to reconnect')
                data_collection_client.connect_to_server()
            else:
                print(f'--> Sent message on topic "{data_collection_client.data_collection_topic}":\n{payload}')

            time.sleep(3)

            fuelLevel = fuelLevel - 0.3
            if fuelLevel < 1:
                fuelLevel = 100

        data_collection_client.disconnect_from_server()

推荐阅读