【问题标题】:Tkinter GUI and Signal.py - ValueError: signal only works in main threadTkinter GUI 和 Signal.py - ValueError:信号仅在主线程中有效
【发布时间】:2020-10-07 10:32:39
【问题描述】:

大家好

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

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

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

代码示例Here

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

文件“/usr/lib/python3.7/signal.py”,第 47 行,在信号中 handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler)) ValueError:信号仅在主线程中起作用

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

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

【问题讨论】:

  • 我通常会添加一个,但由于需要额外的 KAAIoT 设置而跳过了它。我在尝试 1 下添加了一个基本(但仍然很长)的脚本链接

标签: python tkinter signals mqtt


【解决方案1】:

您可以将 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()

【讨论】:

  • 哇,我什至不知道这是一个选项。当我通过另一个带有线程的类运行它时,它导致了错误,但以某种方式运行它在这里线程工作。为我省了很多麻烦,非常感谢!如果可以的话,我会投票 2 倍
猜你喜欢
  • 1970-01-01
  • 2014-11-06
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 1970-01-01
相关资源
最近更新 更多