Python Tkinter线程化在GUI中使用更改页面
我想在tkinter GUI的两个页面上有两个实时绘图,带有停止实时更新的按钮。到目前为止,我已经成功地在我的第一页中创建了一个实时绘图。但是,我在其他函数中创建线程时遇到问题Python Tkinter线程化在GUI中使用更改页面,python,multithreading,tkinter,Python,Multithreading,Tkinter,我想在tkinter GUI的两个页面上有两个实时绘图,带有停止实时更新的按钮。到目前为止,我已经成功地在我的第一页中创建了一个实时绘图。但是,我在其他函数中创建线程时遇到问题 api = csb.SeaBreezeAPI() devices = list_devices() #to get the serial number of the device spec = sb.Spectrometer.from_serial_number("FLMS15412") xs =
api = csb.SeaBreezeAPI()
devices = list_devices() #to get the serial number of the device
spec = sb.Spectrometer.from_serial_number("FLMS15412")
xs = spec.wavelengths()
ys = spec.intensities()
fig1 = Figure(figsize=(10,6),tight_layout=True)
ax1 = fig1.add_subplot(111)
root = tk.Tk()
root.configure(background = 'light blue')
root.geometry("1400x800")
canvas1=FigureCanvasTkAgg(fig1,master=root)
canvas1.get_tk_widget().place(x=5,y=55)
cond = False
def starts():
root.after(1,starts)
cond = False
def plot_data():
if (cond == True):
ax1.cla()
ax1.plot(spec.wavelengths(),spec.intensities
(correct_dark_counts=True),'w',linewidth=1.0)
ax1.set_xlabel('Wavelength (nm)')
ax1.set_ylabel('Intensity (a.u.)')
ax1.set_xlim(200,1000)
ax1.set_ylim(0,60000)
ax1.set_facecolor('#1B1B2A')
ax1.grid(color='w',linestyle='--',linewidth=0.2)
canvas1.draw()
root.after(1,plot_data)
def plot_start():
global cond
cond = True
def plot_stop():
global cond
cond = False
root.update()
startplot = tk.Button(root, text = "Start", font = ('calibri', 12), command = lambda: plot_start())
startplot.place(x=5,y=25)
root.update()
stopplot = tk.Button(root, text = "Stop", font = ('calibri', 12), command = lambda: plot_stop())
stopplot.place(x=65,y=25)
root.update()
start = tk.Button(root, text = "Stage", font = ('calibri', 12),
command=threading.Thread(target=plot_data).start())
start.place(x=125,y=25)
threading.Thread(target=plot_data).start()
root.after(1,plot_data)
root.mainloop()
这是单个页面中实时绘图的最小代码。我想创建另一个带有另一个live plot的页面。我怎样才能用tkinter做到这一点。任何帮助都将不胜感激。下面是一个如何将值打印到windows的示例(不确定这是否是@TheLizzard所说的不做的,但这很有效(至少看起来是这样)):
一些代码只是为了外观,但主要部分是两个函数。它们在不同的线程上运行,只需更新textvariable,这使它变得非常简单。另外,请记住在循环之间放置一些暂停(就像我在
睡眠(0.2)
中所做的那样),否则只运行while循环将冻结GUI(值将被更新,但不可能与之交互)您可以使用TopLevel并几乎复制代码。如果我使用TopLevel,它是否仍在主循环中?我可以在顶级窗口中使用另一个线程吗?将command=threading.thread(…).start()
更改为command=threading.thread(…).start
在使用tkinter时也不要使用线程。有时,如果您尝试从不同的线程访问tkinter,tkinter会崩溃。但这应该不是什么大问题,您仍然可以从一个线程更改小部件属性,同时将所有小部件保持在同一个线程(包括windows)中为什么要使用\u thread.start\u new\u thread
而不是threading.thread
?@TheLizzard,因为我知道如何更好地使用它;我也研究过线程,但在这种情况下使用\u-thread
要容易得多(至少对我来说),但是如何启动线程是我唯一知道的\u-thread
@matiss这非常有用,正是我想要的!我们是否可以在第一页添加一个按钮,以便在按下按钮后弹出第二页?@NicoleWaves是的,这是可能的,但您希望线程从开始运行还是仅在窗口打开时运行?实际上,我认为如果从一开始就运行另一个线程,可能会更容易,也可能更好too@NicoleWaves好的,我编辑的代码现在应该可以工作了
from tkinter import Tk, Toplevel, Label, StringVar, Button
from _thread import start_new_thread
from time import sleep
def update_root():
counter = 0
while True:
root_var.set(f'{counter}')
sleep(0.2)
counter += 1
def update_tp():
counter = 0
while True:
tp_var.set(f'{counter}')
sleep(0.2)
counter += 1
def second_window():
tp = Toplevel(root)
tp.title('Window 2')
tp_label = Label(tp, textvariable=tp_var, font='default 20 normal')
tp_label.pack(padx=200, pady=50)
root = Tk()
root.title('Window 1')
root_var = StringVar()
root_label = Label(root, textvariable=root_var, font='default 20 normal')
root_label.pack(padx=200, pady=50)
Button(root, text='Open other window', command=second_window).pack()
tp_var = StringVar()
start_new_thread(update_root, ())
start_new_thread(update_tp, ())
root.mainloop()