multithreading - Tkinter python中的线程
问题描述
我正在尝试在 tkinter GUI 中运行无限任务(直到被杀死)。在执行此任务后,我尝试使用线程来停止 GUI 冻结和无限挂起。我的期望是线程会停止 GUI(主循环)挂起,但事实并非如此。附上我的代码。有任何想法吗?我调用线程函数的代码中只有一行。
问候,
约旦。
import nidaqmx.system
import nidaqmx
import numpy as np
import matplotlib.pyplot as plt
#from nidaqmx.stream_readers import AnalogMultiChannelReader, DigitalMultiChannelReader
#from nidaqmx.stream_writers import AnalogSingleChannelWriter
Volts = nidaqmx.constants.VoltageUnits.VOLTS
system = nidaqmx.system.System.local()
system.driver_version
from nidaqmx import stream_writers
#from nidaqmx.constants import LineGrouping
#from nidaqmx.constants import TerminalConfiguration
import time
import os
from PIL import Image
import tkinter as tk
from PIL import ImageTk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import threading
dirpath = os.getcwd()
os.chdir(dirpath)
filename = r'Cutera_2.jpg'
img = Image.open(filename)
img.save('Cutera_logo.ico')
logo = dirpath + '\Cutera_logo.ico'
Astrum = dirpath + '\Astrum_board.png'
img = Image.open(Astrum) # image extension *.png,*.jpg
width, height = img.size
enlarge = 1.75
new_width = int(width*enlarge)
new_height = int(height*enlarge)
img = img.resize((new_width, new_height), Image.ANTIALIAS)
img.save('Astrum2.png')
Astrum2 = dirpath + '\Astrum2.png'
system = nidaqmx.system.System.local()
print(system.driver_version)
for device in system.devices:
dev = str(device).split('=')[1].split(')')[0]
print(device)
print(dev)
sample_clock = '/'+dev+'/ai/SampleClock'
def arm_laser(dev,state):
if state == 'on':
state = True
elif state == 'off':
state = False
with nidaqmx.Task("arm") as arm:
arm.do_channels.add_do_chan(dev+"/port1/line0")
arm.write(state, auto_start=True)
def current_to_voltage(current): #gives command voltage for desired current 50mV = 1A
voltage = current/20
return float(voltage)
#fire_astrum(dev,ana_out,ana_in,N,pulse_count,pulse_on,pulse_off,command,mode)
def fire_single_shot(dev,channel,pulse_duration,N,command):
channel = dev +'/' + channel
arm_laser(dev,'on') # Sends 5V to Astrum to arm laser diode
time.sleep(0.2) # wait for 100ms before data stream
with nidaqmx.Task() as task:
samples = np.append(command*np.ones(1),np.zeros(1))
task.ao_channels.add_ao_voltage_chan(channel)
task.timing.cfg_samp_clk_timing(rate=1/pulse_duration*1000, sample_mode= nidaqmx.constants.AcquisitionType.FINITE, samps_per_chan = N)
Writer = stream_writers.AnalogSingleChannelWriter(task.out_stream, auto_start=True)
Writer.write_many_sample(samples)
task.wait_until_done(timeout=10)
time_vec = np.linspace(0, (pulse_duration+pulse_duration)*int(1), num=N, endpoint=True)
print('length of time vec = ' + str(len(time_vec)))
print('length of trigger = ' + str(len(samples)))
return time_vec, samples
arm_laser(dev,'off')
def fire_burst(dev,channel,pulse_on,pulse_off,pulse_count,N,command):
channel = dev +'/' + channel
arm_laser(dev,'on') # Sends 5V to Astrum to arm laser diode
time.sleep(0.2) # wait for 100ms before data stream
with nidaqmx.Task() as task:
duty = pulse_on/(pulse_on+pulse_off) # duty cycle in %
#N = 2**8 # no of points in stream array (8-bit)
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))
task.ao_channels.add_ao_voltage_chan(channel)
task.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))
Writer = stream_writers.AnalogSingleChannelWriter(task.out_stream, auto_start=True)
Writer.write_many_sample(samples)
task.wait_until_done(timeout=60) # Alternative command lokk at API
trigger = np.tile(samples,pulse_count)
time_vec = np.linspace(0, (pulse_on+pulse_off)*pulse_count, num=len(trigger), endpoint=True)
print('length of time vec = ' + str(len(time_vec)))
print('length of trigger = ' + str(len(trigger)))
return time_vec, trigger
arm_laser(dev,'off')
def fire_continuous(dev,channel,pulse_on,pulse_off,N,command):
channel = dev +'/' + channel
arm_laser(dev,'on') # Sends 5V to Astrum to arm laser diode
time.sleep(0.2) # wait for 100ms before data stream
with nidaqmx.Task() as task:
duty = pulse_on/(pulse_on+pulse_off) # duty cycle in %
#N = 2**8 # no of points in stream array (8-bit)
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))
task.ao_channels.add_ao_voltage_chan(channel)
task.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N, sample_mode= nidaqmx.constants.AcquisitionType.CONTINUOUS)
Writer = stream_writers.AnalogSingleChannelWriter(task.out_stream, auto_start=True)
Writer.write_many_sample(samples)
task.wait_until_done(timeout=nidaqmx.constants.WAIT_INFINITELY) # Alternative command lokk at API
#def fire_continuous(dev,channel,pulse_on,pulse_off,N,command): # Fire continuous has to be threaded
# channel = dev +'/' + channel
#
# arm_laser(dev,'on') # Sends 5V to Astrum to arm laser diode
# time.sleep(0.2) # wait for 100ms before data stream
#
# task = nidaqmx.Task()
# duty = pulse_on/(pulse_on+pulse_off) # duty cycle in %
# #N = 2**8 # no of points in stream array
# 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))
# task.ao_channels.add_ao_voltage_chan(channel)
# task.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N, source=sample_clock, sample_mode= nidaqmx.constants.AcquisitionType.CONTINUOUS)
# Writer = stream_writers.AnalogSingleChannelWriter(task.out_stream, auto_start=True)
# Writer.write_many_sample(samples)
## task.start()
#root = tk.Toplevel
window = tk.Tk()
window.resizable(width=True, height=True)
#window.withdraw()
window.iconbitmap(logo)
window.configure(background='white')
window.geometry("1700x1500") # This sets the Window size to work with
#window.geometry("600x500") # This sets the Window size to work with
window.title('Astrum laser pulser')
defaultbg = window.cget('bg')
img = ImageTk.PhotoImage(Image.open(Astrum))
panel = tk.Label(window, image = img,background="white")
panel.place(relx=.7, rely=.65)
fig = plt.Figure(figsize=(5,4), dpi=100)
fig.tight_layout(True)
ax1 = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig, window)
fig.canvas.draw()
canvas.get_tk_widget().place(relx=0.55, rely=0.35, anchor=tk.W)
trig, = ax1.plot([],[], color = 'g')
ax1.set_title('Pulse trigger')
ax1.set(xlabel='time (ms)', ylabel='current (A)')
ax1.grid(linewidth=0.7, linestyle=':')
def update_plot(x,y):
trig.set_data(x,y)
ax1.set_xlim(0, max(x))
ax1.set_ylim(0, 1.1*max(y))
fig.canvas.draw()
fig.canvas.flush_events()
def get_trigger(pulse_count,pulse_on,pulse_off,N,command):
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)
samples = np.append(command*np.ones(array_on),np.zeros(array_off))
trigger = np.tile(samples,pulse_count)
return trigger
l = tk.Label(window, bg='white', fg='black', width=20, text='Diode current = 0.0A')
l.pack()
def print_selection(v):
l.config(text='Diode current = ' + v + "A")
global variable
#print(v)
variable = v
def savecurrent():
print("current selcted was = " + variable + "A")
return float(variable)
s = tk.Scale(window, label='Diode current (A)', from_=0, to=70, orient=tk.HORIZONTAL, length=1400, showvalue=2,tickinterval=5, resolution=0.5, command=print_selection)
s.pack()
def selected():
print(var.get())
def fire_laser():
#global final
print(var.get(),get_pulse_on(),get_pulse_off(),get_pulse_count(),get_trig_delay())
print("Enter function to get configuration, write configuration then fire laser...")
diode_curr = savecurrent()
print(diode_curr)
if var.get() == 'SINGLE SHOT':
data = fire_burst(dev,'ao0',float(get_pulse_on()),float(get_pulse_off()),int(1),1000,current_to_voltage(diode_curr))
mode = get_trigger(int(1),float(get_pulse_on()),float(get_pulse_off()),1000,float(diode_curr))
t = data[0]
#mode = data[1]
print('single shot fired')
elif var.get() == 'CONTINUOUS':
#fire_continuous(dev,channel,pulse_on,pulse_off,N,command)
mode = get_trigger(int(get_pulse_count()),float(get_pulse_on()),float(get_pulse_off()),1000,float(diode_curr))
threading.Thread(target=fire_continuous(dev,'ao0',float(get_pulse_on()),float(get_pulse_off()),1000,current_to_voltage(diode_curr))).start()
t = np.linspace(0, (float(get_pulse_on())+float(get_pulse_off()))*int(get_pulse_count()), num=len(mode), endpoint=True)
#t = data[0]
print('continuous pulse modulation')
elif var.get() == 'PULSE TRAIN':
data = fire_burst(dev,'ao0',float(get_pulse_on()),float(get_pulse_off()),int(get_pulse_count()),1000,current_to_voltage(diode_curr))
mode = get_trigger(int(get_pulse_count()),float(get_pulse_on()),float(get_pulse_off()),1000,float(diode_curr))
t = data[0]
#mode = data[1]
print('A burst of ' + str(int(get_pulse_count())) + ' pulses fired')
update_plot(t,mode)
#final = [var.get(),var1.get(),var2.get(),get_noise_scan(),get_power_scan(), get_delay(), get_cycle(), get_dt(), get_temp(), get_step()]
# window.quit()
# window.destroy()
# return final
def stop_laser():
#global final
#fire_astrum(dev,'ao0','ai0:1',1000,int(1),float(get_pulse_on()),float(get_pulse_off()),current_to_voltage(0),'train')
print("Enter function here to kill the laser")
look = get_trigger(int(1),float(get_pulse_on()),float(get_pulse_off()),1000,float(0))
t = list(range(len(look)))
print('laser stopped')
update_plot(t,look)
arm_laser(dev,'off')
# final = [var.get(),var1.get(),var2.get(),get_noise_scan(),get_power_scan(), get_delay(), get_cycle(), get_dt(), get_temp(), get_step()]
# window.quit()
# window.destroy()
# return final
def get_pulse_on():
on = entry1.get()
print(on)
return on
def get_pulse_off():
off = entry2.get()
print(off)
return off
def get_pulse_count():
count = entry3.get()
print(count)
return count
def get_trig_delay():
delay = entry4.get()
print(delay)
return delay
def get_power_scan():
p = entry4.get()
print(p)
return p
# if var1.get() == "BRF" or var.get() == "single" or (var1.get() == "BRF" and var2.get() == "BRF"):
# brf.config(state=tk.DISABLED, selectcolor = "snow")
#
# elif var1.get() == "SHG" or var1.get() == "THG" or var1.get() == "ETA" or var1.get() == "MAIN TEC":
# brf.config(state=tk.ACTIVE, selectcolor = "peach puff")
#
# if var1.get() == "SHG" or var.get() == "single" or (var1.get() == "SHG" and var2.get() == "SHG"):
# shg.config(state=tk.DISABLED, selectcolor = "snow")
#
# elif var1.get() == "BRF" or var1.get() == "THG" or var1.get() == "ETA" or var1.get() == "MAIN TEC":
# shg.config(state=tk.ACTIVE, selectcolor = "spring green")
#
# if var1.get() == "THG" or var.get() == "single" or (var1.get() == "THG" and var2.get() == "THG"):
# thg.config(state=tk.DISABLED, selectcolor = "snow")
#
# elif var1.get() == "BRF" or var1.get() == "SHG" or var1.get() == "ETA" or var1.get() == "MAIN TEC":
# thg.config(state=tk.ACTIVE, selectcolor = "thistle1")
#
# if var1.get() == "ETA" or var.get() == "single" or (var1.get() == "ETA" and var2.get() == "ETA"):
# eta.config(state=tk.DISABLED, selectcolor = "snow")
#
# elif var1.get() == "BRF" or var1.get() == "SHG" or var1.get() == "THG" or var1.get() == "MAIN TEC":
# eta.config(state=tk.ACTIVE, selectcolor = "sky blue")
#
# if var1.get() == "MAIN TEC" or var.get() == "single" or (var1.get() == "MAIN TEC" and var2.get() == "MAIN TEC"):
# maint.config(state=tk.DISABLED, selectcolor = "snow")
#
# elif var1.get() == "BRF" or var1.get() == "SHG" or var1.get() == "THG" or var1.get() == "ETA":
# maint.config(state=tk.ACTIVE, selectcolor = "salmon")
############
trigg = tk.StringVar()
check1 = tk.Checkbutton(window, text='Trigger',
command=get_power_scan, variable = trigg,
onvalue="Yes", offvalue="No")
#
check1.place(x=200,y=100+15*20*2)
check1.deselect()
#############
mode = ["SINGLE SHOT", "CONTINUOUS", "PULSE TRAIN"]
#get_scan
# button = tk.Button(window, font="Heltavica",text ="PROCEED", command=get_scan)
# button.config(bd=8, font="Ariel", justify="center")
# button.place(relx=.39, rely=0.9)
#used to get the 'value' property of a tkinter.Radiobutton
var = tk.StringVar() #MODE
var2 = tk.StringVar() #FIRE
var3 = tk.StringVar() #STOP
fire = tk.Button(window, width=8 , bd=4, text="FIRE", command = fire_laser, activebackground="red")#, onvalue=1, offvalue=0)
fire.place(x=200,y=100+15*35*1)
#fire.deselect()
#fire.config(selectcolor = "snow")
#fire.pack()
#fire.update()
stop = tk.Button(window, width=8 , bd=4, text="STOP", command = stop_laser, activebackground="green")#, onvalue=1, offvalue=0)
stop.place(x=600,y=100+15*35*1)
#stop.deselect()
#stop.config(selectcolor = "snow")
#stop.pack()
#stop.update()
ss = tk.Radiobutton(window, selectcolor = "peach puff", width=12, bd=4, text="SINGLE SHOT", variable=var, value = mode[0], command = selected , indicatoron = 0)#, onvalue=1, offvalue=0)
ss.place(x=200,y=100+15*5*1)
ss.select()
#ss.config(selectcolor = "snow")
#ss.pack
ss.update()
c = tk.Radiobutton(window, selectcolor = "spring green", width=12 , bd=4, text="CONTINUOUS", variable=var, value = mode[1], command = selected , indicatoron = 0)#, onvalue=1, offvalue=0)
c.place(x=200,y=100+15*10*1)
c.deselect()
#c.config(selectcolor = "snow")
#c.pack
c.update()
pt = tk.Radiobutton(window, selectcolor = "thistle1" , width=12 , bd=4, text="PULSE TRAIN", variable=var, value = mode[2], command = selected , indicatoron = 0)#, onvalue=1, offvalue=0)
pt.place(x=200,y=100+15*15*1)
pt.deselect()
#pt.config(selectcolor = "snow")
#pt.pack
pt.update()
entry1 = tk.Entry(window, width=4)
entry1.insert(0, "40")
entry1.place(x=500,y=30+100+15*5*1)
entry1.config(bd=2, font="Ariel", justify="center",state=tk.NORMAL)
entry2 = tk.Entry(window, width=4)
entry2.insert(0, "15")
entry2.place(x=500,y=30+100+15*10*1)
entry2.config(bd=2, font="Ariel", justify="center",state=tk.NORMAL)
entry3 = tk.Entry(window, width=4)
entry3.insert(0, "10")
entry3.place(x=500,y=30+100+15*15*1)
entry3.config(bd=2, font="Ariel", justify="center",state=tk.NORMAL)
entry4 = tk.Entry(window, width=4)
entry4.insert(0, "100")
entry4.place(x=500,y=30+100+15*20*1)
entry4.config(bd=2, font="Ariel", justify="center",state=tk.NORMAL)
L = tk.Label(window, text = "Pulse on (ms) ", font="Ariel", width=22, height = 1 , background = defaultbg)
L.place(x=400,y=100+15*5*1)
L2 = tk.Label(window, text = "Pulse off (ms) " , font="Ariel", width=22, height = 1 , background = defaultbg)
L2.place(x=400,y=100+15*10*1)
L3 = tk.Label(window, text = "Pulse count " , font="Ariel", width=22, height = 1 , background = defaultbg)
L3.place(x=400,y=100+15*15*1)
L4 = tk.Label(window, text = "Delay (ms) " , font="Ariel", width=22, height = 1 , background = defaultbg)
L4.place(x=400,y=100+15*20*1)
window.mainloop()
解决方案
你想替换:
threading.Thread(target=fire_continuous(dev,channel,pulse_on,pulse_off,N,command)).start()
with(实际参数,而不是这些占位符)
threading.Thread(target=fire_continuous, args=(dev,channel,pulse_on,pulse_off,N,command)).start()
注意args=
第二个版本中的参数。
在第一个版本中使用括号调用fire_continuous
会立即调用该函数(在主线程内)。的target
参数threading.Thread
需要一个可调用的(尚未调用)
推荐阅读
- python - 交叉验证:无法使用 clear_session() 清除模型来训练新模型
- mysql - 在 MySQL 中生成一个随机顺序的整数序列
- mysql - 如何在 sql 中使用行号创建视图?SQL
- windows - 在 Edge 中使用 Powershell 激活 Power BI 全屏模式
- robotframework - 对于 Chrome,我想使用套件设置和套件拆解,对于 IE 浏览器,我想使用测试设置和测试拆解
- node.js - 在我得到一个 set-cookie 作为响应后,不会在请求中保存和传输
- google-apps-script - onEdit() 将行移动到其他工作表有时会将行移动到目标行下方
- c++ - std::make_shared 和 std::make_unique 有“nothrow”版本吗?
- python - 如何在 ChainMap 中打印某个元素
- android - 更改活动的语言也反映在以前创建的活动中