【问题标题】:Call thread with loop out of gui without freezing gui在不冻结 gui 的情况下从 gui 循环调用线程
【发布时间】:2019-10-24 12:47:03
【问题描述】:

我想运行一个测量程序,该程序在同一时期从两个不同的设备获取测量值。我想在一个小 gui 内开​​始和停止测量。由于我需要一个 while 循环来测量、绘制和保存其中一个测量值并运行它,直到我用停止按钮中断它,我想我需要将它作为不同的线程调用以不冻结 gui 并能够使用停止按钮。另外我认为我不应该使用 .join() 来不冻结 gui。但不知何故,我的 gui 似乎仍然冻结,我无法使用停止按钮。我已经在论坛中阅读过类似的问题,但我无法弄清楚我做错了什么。 这实际上是我第一个使用线程的项目,所以我对选项和事件没有任何经验,但我也看不出它们会如何帮助我。

所以我有一个类来与我的 arduino 通信,一个与 saleae(第二个设备)通信,还有一个 data_treatment 类来绘制和保存来自 arduino 的数据。

所以我主要有一个带有开始和停止按钮的小 gui。当我按下开始按钮时,我想启动 saleae 测量(它可以在自己的程序中舒适地运行)并调用我的 ardunio 类的记录功能。该函数有一个 while 循环,它读取值并将它们提供给 data_treatment 函数。当我按开始时,它会启动 saleae 测量和 arduino 测量,一切都按计划进行,但我不能按停止,因为 gui 似乎在等待另一个威胁,直到我按停止才结束。

所以这里是我的主函数(cambine_func)只是一个可以通过按钮调用几个函数的函数),下面是arduino类:

if __name__ == '__main__':
window = gui.Window("Measurement")

start_button = window.add_button("Start")
start_button.pack(pady = 20)
gui.on("btnPress", start_button, lambda: combine_funcs(saleae.start_measurement(),
                                                       threading.Thread(target = arduino.record_values(300)).start()))

stop_button = window.add_button("Stopp")
stop_button.pack(pady = 20)
gui.on("btnPress", stop_button, lambda: combine_funcs(saleae.end_measurement(),
                                                      saleae.save_data(),
                                                      arduino.close_port(),
                                                      window.destroy()))

window.start()




import time

class Arduino_communication:
"""
reads what comes in from Arduino and transformes it into single values
"""
def __init__(self, arduino, data_treatment):
    self.arduino = arduino
    self.data_treatment = data_treatment
    self.interrupted = False

def record_values(self, measurement_period):
    """
    reads values from the Arduino and converts it into single values,
    counts faulty lines received from Arduino
    :return: array of 6 columns (roll, pitch, yaw, x-position, y-position, z-position)
    """
    faulty_values = 0
    data = [0, 0, 0, 0, 0, 0]
    start_time = float(time.time())
    time_vector = []

    while self.interrupted == False:

        self.arduino.flushInput()               # delete what's in buffer
        self.arduino.readline()                 # read a byte string and throw away (deleting buffer may lead to uncomplete line)
        b = self.arduino.readline()             # read next line
        time_vector.append(float(time.time())-start_time)

        try:
            string_n = b.decode()               # decode byte string into Unicode
        except UnicodeDecodeError:              # Arduino sometimes sends faulty lines
            faulty_values += 1
        string = string_n.rstrip()              # remove \n and \r
        single_strings = string.split('/')
        try:
            data = [float(j) for j in single_strings]  # convert string to float
        except (ValueError, UnicodeDecodeError): # Arduino sometimes sends faulty lines
            faulty_values += 1

        self.data_treatment.plot_new_data_line(time_vector[-1], data)
        self.data_treatment.write_to_csv(time_vector[-1], data)

    print('Es gab ', faulty_values, ' fehlerhafte Übertragungen.')
    self.data_treatment.finish_plotting()

def close_port(self):
    """
    stops measurement and closes arduino port
    """
    self.interrupted = True
    self.arduino.close()

【问题讨论】:

    标签: python multithreading user-interface


    【解决方案1】:

    你有:

    threading.Thread(target = arduino.record_values(300)).start()
    

    这会调用该方法,然后以结果为目标启动一个线程。

    你想要的地方:

    threading.Thread(target=arduino.record_values, args=[300]).start()
    

    这会启动一个带有目标arduino.record_values 和参数300 的线程。

    您可能希望保留该线程,以便在录制线程正在录制时防止开始按钮启动另一个录制线程。

    【讨论】:

    • 感谢您的快速答复!我试过了,但后来 arduino 只测量了一次,然后 gui 就关闭了。这意味着 tho 循环不起作用,这对我来说毫无意义。
    • 我不知道您使用的是哪个 GUI 库,但大多数都需要调用 GUI 主循环来保持程序及其窗口打开。在 PyGTK 中,这是gtk.mainloop()
    • 哦,那是真的,谢谢。但是以某种方式将 window.start() 更改为 window.mainloop() 并没有帮助......
    • 我认为这行不通。我想知道您使用的是什么 GUI 库,以便查找等价物。
    • 哦,好的,对不起。我使用的那个只是叫 gui,但我用 tkinter 尝试了它,我猜它是 .mainloop,但我无法让它在那里工作
    【解决方案2】:

    我想不出我认为可行的解决方案,但我发现了这个answer,我可以适应我的项目,现在它可以按我的意愿工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-30
      • 2014-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多