从GUI循环调用线程而不会冻结gui

时间:2019-10-24 12:47:03

标签: python multithreading user-interface

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

因此,我有一个与arduino通信的类,一个与Saleae(第二设备)通信的类,以及一个data_processing类,用于绘制和保存来自arduino的数据。

所以在我的主菜单中,我有一个带有启动和停止按钮的小GUI。当我按下开始按钮时,我想启动saleae测量(在自己的程序中舒适地运行)并调用ardunio类的记录函数。该函数有一个while循环,该循环读取值并将其提供给data_treatment函数。当我按下开始键时,它会开始测量saleae和arduino,并且一切都按计划进行,但是我无法按一下Stop,因为gui似乎正在等待其他威胁,直到我按下Stop为止。 / p>

所以这是我的主要功能(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()

2 个答案:

答案 0 :(得分:0)

您有:

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

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

您想要的地方:

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

这将从目标arduino.record_values和参数300开始线程。

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

答案 1 :(得分:0)

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