简体   繁体   English

使用 window.after 在 tkinter 中进行多线程处理

[英]Multithreading in tkinter using window.after

I'm having a rough time trying to create threads inside a tkinter GUI.我在尝试在 tkinter GUI 中创建线程时遇到了困难。 To give some background on what I would like the code to do.提供一些关于我希望代码做什么的背景。 This is a GUI that when the log buttons are pressed (eg log_1 ).这是一个 GUI,当按下日志按钮时(例如log_1 )。 I'd like to send a continuous command to fire a laser and eventually (after I tackle the current problem) log the subsequent parameters.我想发送一个连续的命令来发射激光并最终(在我解决当前问题之后)记录后续参数。

However, my issue is that I have 5 lasers needing to be fired at the same time (or very close to) and the more lasers I have in the logging state ON the more the time delay between the lasers firing.但是,我的问题是我需要同时(或非常接近)发射 5 个激光器,并且处于记录状态 ON 的激光器越多,激光器发射之间的时间延迟就越长。 I guess this is an issue because my: fire_all() function in conjunction with the window after(100, fire_all) is not a threaded process so having more lasers firing results in more of a time delay between the onset of the command to fire.我想这是一个问题,因为我的: fire_all()函数与window after(100, fire_all)不是一个线程过程,所以有更多的激光发射会导致发射命令开始之间的时间延迟更多。

My code is below.我的代码如下。 Does anyone have any suggestions how to implement this properly?有没有人有任何建议如何正确实施?

# start the GUI

import tkinter as tk

window = tk.Tk()

def fire_astrum(dev):  # N = 100 # no of points in stream array, pulse_count = int(1) # no of desired pulses in pulse train #command is command volatge
    #dev,ana_out,ana_in,N,pulse_count,pulse_on,pulse_off,command
    #dev = 'Dev1'
    ana_out = 'ao0'
    ana_in = "ai0:1"# for non consecutive channels use: "Dev0/ai0:Dev0/ai4"
    N = 100
    pulse_count = 10
    pulse_on = 45
    pulse_off = 15
    command = 3.5

    channel = dev +'/' + ana_out
    tot = dev + "/" + ana_in
    duty = pulse_on/(pulse_on+pulse_off) # duty cycle in %
    array_on = int(N*duty) # on values in array
    array_off = int(N-array_on) # off values in array
    samples = np.append(command*np.ones(array_on),np.zeros(array_off)) # command is command voltage (IPROG), sets up stream array to send to NI box
    curr = np.empty((2,pulse_count*len(samples))) # Empty arrays for IMON,VMON
    error = np.uint32(np.empty((3,pulse_count*len(samples)))) # # Empty arrays for Digital inputs with pull-up resistors (READY, ERR1 & ERR2)
    #sample_clock = '/'+dev+'/ai/SampleClock'

    arm_laser(dev,'on') # Sends 5V to Astrum to arm laser diode
    time.sleep(0.3) # wait for 300ms before data stream

    with nidaqmx.Task() as writeTask, nidaqmx.Task() as readcurr, nidaqmx.Task(): # as digitalread:#, nidaqmx.Task() as readvolt:
        writeTask.ao_channels.add_ao_voltage_chan(channel,units = Volts)
        writeTask.ao_channels.all.ao_max = 4 # Hard clamp Limit to 4V to protect laser diode
        writeTask.ao_channels.all.ao_min = 0 # Set baseline to 0V (ground loop protection)
        readcurr.ai_channels.add_ai_voltage_chan(tot, units = Volts,terminal_config = TerminalConfiguration.RSE) # define differntial NRE connfig of channels
        #print(read_curr.ai_term_cfg)
        #digitalread.di_channels.add_di_chan(dev + '/port0/line0:2',line_grouping=LineGrouping.CHAN_PER_LINE)
        #writeTask.triggers.start_trigger.cfg_dig_edge_start_trig('/' + dev +'/' + terminal) #Setting the trigger on the analog input
        writeTask.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N,sample_mode= nidaqmx.constants.AcquisitionType.FINITE , samps_per_chan= pulse_count*len(samples))
        readcurr.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N, sample_mode= nidaqmx.constants.AcquisitionType.FINITE , samps_per_chan= pulse_count*len(samples))
        #digitalread.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N, sample_mode= nidaqmx.constants.AcquisitionType.FINITE , samps_per_chan= pulse_count*len(samples))
        reader_curr = AnalogMultiChannelReader(readcurr.in_stream)
        #digital = DigitalMultiChannelReader(digitalread.in_stream)
        writer = AnalogSingleChannelWriter(writeTask.out_stream, auto_start=True)
        writer.write_many_sample(samples)
        time_vec = np.linspace(0, (pulse_on+pulse_off)*pulse_count, num=len(curr[0]), endpoint=True)
        reader_curr.read_many_sample(data = curr,number_of_samples_per_channel = pulse_count*len(samples), timeout = nidaqmx.constants.WAIT_INFINITELY)# read from DAQ
        #digital.read_many_sample_port_uint32(data = error,number_of_samples_per_channel = pulse_count*len(samples), timeout = nidaqmx.constants.WAIT_INFINITELY)# read from DAQ
        curr = np.around(curr, 6) # Round all values to 6 decimals to avoid overflow
        error = np.around(error, 6) # Round all values to 6 decimals to avoid overflow
        print("The channels linked to WriteTask are: ")
        for i in writeTask.ao_channels:
            print(i)
        print("The channels linked to ReadTask are: ")
        for j in readcurr.ai_channels:
            print(j)
        #################  Astrum parameters  #########################
        imon = curr[0]
        vmon = curr[1]
        ready = error[0]
        err1 = error[1]
        err2 = error[2]
        trigger = np.tile(samples,pulse_count)
        ###############################################################
        arm_laser(dev,'off')
        ###############################################################
        V = np.max(vmon)
        I = np.max(imon)
        #for j in range(9):
        laser_1[6].config(text = V)
        laser_1[7].config(text = I)

def log1():
    if log_1.config('text')[-1] =='ON':
        log_1.config(text='OFF', bg="red",activebackground="red",textvariable=0)
        print(log_1.config('textvariable')[-1])
    else:
        log_1.config(text='ON', bg="green",activebackground="green",textvariable=1)
        print(log_1.config('textvariable')[-1])

def log2():
    if log_2.config('text')[-1] =='ON':
        log_2.config(text='OFF', bg="red",activebackground="red",textvariable=0)
        print(log_2.config('textvariable')[-1])
    else:
        log_2.config(text='ON', bg="green",activebackground="green",textvariable=1)
        print(log_2.config('textvariable')[-1])

def log3():
    if log_3.config('text')[-1] =='ON':
        log_3.config(text='OFF', bg="red",activebackground="red",textvariable=0)
        print(log_3.config('textvariable')[-1])
    else:
        log_3.config(text='ON', bg="green",activebackground="green",textvariable=1)
        print(log_3.config('textvariable')[-1])

def log4():
    if log_4.config('text')[-1] =='ON':
        log_4.config(text='OFF', bg="red",activebackground="red",textvariable=0)
        print(log_4.config('textvariable')[-1])
    else:
        log_4.config(text='ON', bg="green",activebackground="green",textvariable=1)
        print(log_4.config('textvariable')[-1])

def log5():
    if log_5.config('text')[-1] =='ON':
        log_5.config(text='OFF', bg="red",activebackground="red",textvariable=0)
        print(log_5.config('textvariable')[-1])
    else:
        log_5.config(text='ON', bg="green",activebackground="green",textvariable=1)
        print(log_5.config('textvariable')[-1])

##### logging button lasers ###########


log_1 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log1, bg = "red")
log_1.grid(row = 2, column = 8)

log_2 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log2, bg = "red") #, onvalue=1, offvalue=0)
log_2.grid(row = 3, column = 8)

log_3 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log3, bg = "red") #, onvalue=1, offvalue=0)
log_3.grid(row = 4, column = 8)

log_4 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log4, bg = "red") #, onvalue=1, offvalue=0)
log_4.grid(row = 5, column = 8)

log_5 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log5, bg = "red") #, onvalue=1, offvalue=0)
log_5.grid(row = 6, column = 8)


def fire_all():
      #global a
      a = str(log_1.config('textvariable')[-1])
      b = str(log_2.config('textvariable')[-1])
      c = str(log_3.config('textvariable')[-1])
      d = str(log_4.config('textvariable')[-1])
      e = str(log_5.config('textvariable')[-1])

      if a == '1':
          fire_astrum('Dev1')
      if b == '1':
          fire_astrum('Dev2')
      if c == '1':
          fire_astrum('Dev3')
      if d == '1':
          fire_astrum('Dev4')
      if e == '1':
          fire_astrum('Dev5')

      # call this function again in 100 milliseconds

      window.after(100, fire_all)


window.after(100,  fire_all)
window.mainloop()

you can probably launch fire_astrum in a thread from fire_all .你或许可以推出fire_astrum从一个线程fire_all

maybe like this:也许是这样的:

import threading

...
if a == '1':
    threading.Thread(target=lambda dev='Dev1': fire_astrum(dev)).start()
...

It is unclear how long fire_astrum takes to complete;目前还不清楚fire_astrum需要多长时间才能完成; it also sleeps for 300ms;它还休眠 300 毫秒; there is no telling the outcome when fired every 100ms, you'll have to try.每 100 毫秒触发一次时无法知道结果,您必须尝试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM