【问题标题】:Tkinter threading use of change pages in a GUITkinter 线程在 GUI 中使用更改页面
【发布时间】:2021-04-14 17:16:56
【问题描述】:

我想在 tkinter GUI 的两个页面上有两个实时图,并带有按钮来停止实时更新。到目前为止,我已经设法在我的第一页中创建了一个现场图。但是,我在其他函数中创建线程时遇到问题。

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()

这是单个页面中实时绘图的最小代码。我想用另一个实况图创建另一个页面。我怎么能用 tkinter 做到这一点。任何帮助将不胜感激。

【问题讨论】:

  • 您可以使用 TopLevel 并且几乎可以复制代码吗?
  • 如果我使用TopLevel,它不是还在主循环中吗?我可以在顶层窗口中使用另一个线程吗?
  • command = threading.Thread(...).start() 更改为 command = threading.Thread(...).start
  • 在使用 tkinter 时也不要使用线程。如果您尝试从不同的线程访问它,有时 tkinter 会崩溃。
  • 但这应该不是太大的问题您仍然可以从一个线程更改小部件属性,同时将所有小部件保持在同一个线程中(包括窗口)

标签: python multithreading tkinter


【解决方案1】:

这是一个如何将值绘制到窗口的示例(不确定这是否是 @TheLizzard 所说的不应该做的,但这有效(至少看起来如此)):

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()

一些代码只是为了外观,但主要部分是两个功能。它们在单独的线程上运行,只需更新 textvariable 就很容易了。还要记住在循环之间放置一些暂停(就像我对sleep(0.2) 所做的那样),否则仅运行 while 循环会冻结 GUI(值将被更新但无法与之交互)

【讨论】:

  • 你为什么用_thread.start_new_thread而不是threading.Thread
  • @TheLizzard 因为我知道如何更好地使用它;我也研究过线程,但在这种情况下使用_thread 更容易(至少对我来说)但是如何启动线程是我唯一知道的关于_thread
  • @Matiiss 这很有帮助,正是我想要的!我们是否也可以在第一页添加一个按钮,以便在按下它后弹出第二页?
  • @NicoleWaves 是的,这是可能的,但是您希望线程从头开始运行还是仅在窗口打开时运行?实际上我认为如果另一个线程也从头开始运行可能会更容易,也许更好
  • @NicoleWaves 好的,所以我编辑的代码现在应该可以工作了
猜你喜欢
  • 1970-01-01
  • 2021-12-11
  • 2017-02-27
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 2019-06-12
相关资源
最近更新 更多