Как вы запускаете свой собственный код вместе с циклом событий Tkinter?
мой младший брат только начинает заниматься программированием, и для своего проекта Science Fair он делает симуляцию стаи птиц в небе. Он получил большую часть своего кода написано, и это работает хорошо, но птицы должны двигаться каждый момент.
Tkinter, однако, свиньи время для своего собственного цикла событий, и поэтому его код не будет работать. Делать root.mainloop() работает, работает и продолжает работать, и единственное, что он работает, это обработчики событий.
есть ли способ чтобы его код работал вместе с mainloop (без многопоточности, это сбивает с толку, и это должно быть просто), и если да, то что это такое?
прямо сейчас, он придумал уродливый Хак, связывая его
5 ответов:
The решение опубликовано Бьорн приводит к сообщению "RuntimeError: вызов Tcl из разных квартир" на моем компьютере (RedHat Enterprise 5, python 2.6.1). Бьорн, возможно, не получил это сообщение, так как, согласно одно место я проверил, неправильное обращение с резьбой с Tkinter непредсказуемо и зависит от платформы.
проблема, кажется, в том, что
app.start()считается ссылкой на ТЗ, так как приложение содержит элементы ТЗ. Я исправил это с помощью заменаapp.start()Сself.start()внутри__init__. Я также сделал так, что все ссылки на ТЗ находятся либо внутри функция, которая вызываетmainloop()или внутри функции, которые вызываются функция, которая вызываетmainloop()(это, по-видимому, важно, чтобы избежать ошибки "другой квартиры").наконец, я добавил обработчик протокола с обратным вызовом, так как без этого программа выходит с ошибкой, когда окно Tk закрывается пользователь.
измененный код выглядит следующим образом:
# Run tkinter code in another thread import tkinter as tk import threading class App(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.start() def callback(self): self.root.quit() def run(self): self.root = tk.Tk() self.root.protocol("WM_DELETE_WINDOW", self.callback) label = tk.Label(self.root, text="Hello World") label.pack() self.root.mainloop() app = App() print('Now we can continue running code while mainloop runs!') for i in range(100000): print(i)
при написании собственного цикла, как и в симуляции (я предполагаю), вам нужно вызвать
updateфункция, которая делает то, чтоmainloopделает: обновляет окно с вашими изменениями, но вы делаете это в цикле.def task(): # do something root.update() while 1: task()
другой вариант-позволить tkinter выполняться в отдельном потоке. Один из способов сделать это так:
import Tkinter import threading class MyTkApp(threading.Thread): def __init__(self): self.root=Tkinter.Tk() self.s = Tkinter.StringVar() self.s.set('Foo') l = Tkinter.Label(self.root,textvariable=self.s) l.pack() threading.Thread.__init__(self) def run(self): self.root.mainloop() app = MyTkApp() app.start() # Now the app should be running and the value shown on the label # can be changed by changing the member variable s. # Like this: # app.s.set('Bar')будьте осторожны, хотя многопоточное программирование трудно, и это действительно легко стрелять себе в ногу. Например, вы должны быть осторожны при изменении переменных-членов класса sample выше, чтобы не прерывать цикл событий Tkinter.
Это первая рабочая версия того, что будет GPS-считыватель и презентатор данных. tkinter-очень хрупкая вещь с слишком малым количеством сообщений об ошибках. Он не ставит вещи и не говорит, почему большую часть времени. Очень сложно исходить от хорошего разработчика формы WYSIWYG. Во всяком случае, это запускает небольшую процедуру 10 раз в секунду и представляет информацию о форме. Потребовалось время, чтобы это произошло. Когда я попробовал значение таймера 0, форма никогда не появлялась. Теперь у меня болит голова! 10 или больше раз в секунду достаточно хорошо для меня. Я надеюсь, что это поможет кому-то еще. Майк Морроу
import tkinter as tk import time def GetDateTime(): # Get current date and time in ISO8601 # https://en.wikipedia.org/wiki/ISO_8601 # https://xkcd.com/1179/ return (time.strftime("%Y%m%d", time.gmtime()), time.strftime("%H%M%S", time.gmtime()), time.strftime("%Y%m%d", time.localtime()), time.strftime("%H%M%S", time.localtime())) class Application(tk.Frame): def __init__(self, master): fontsize = 12 textwidth = 9 tk.Frame.__init__(self, master) self.pack() tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth, text='Local Time').grid(row=0, column=0) self.LocalDate = tk.StringVar() self.LocalDate.set('waiting...') tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth, textvariable=self.LocalDate).grid(row=0, column=1) tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth, text='Local Date').grid(row=1, column=0) self.LocalTime = tk.StringVar() self.LocalTime.set('waiting...') tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth, textvariable=self.LocalTime).grid(row=1, column=1) tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth, text='GMT Time').grid(row=2, column=0) self.nowGdate = tk.StringVar() self.nowGdate.set('waiting...') tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth, textvariable=self.nowGdate).grid(row=2, column=1) tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth, text='GMT Date').grid(row=3, column=0) self.nowGtime = tk.StringVar() self.nowGtime.set('waiting...') tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth, textvariable=self.nowGtime).grid(row=3, column=1) tk.Button(self, text='Exit', width = 10, bg = '#FF8080', command=root.destroy).grid(row=4, columnspan=2) self.gettime() pass def gettime(self): gdt, gtm, ldt, ltm = GetDateTime() gdt = gdt[0:4] + '/' + gdt[4:6] + '/' + gdt[6:8] gtm = gtm[0:2] + ':' + gtm[2:4] + ':' + gtm[4:6] + ' Z' ldt = ldt[0:4] + '/' + ldt[4:6] + '/' + ldt[6:8] ltm = ltm[0:2] + ':' + ltm[2:4] + ':' + ltm[4:6] self.nowGtime.set(gdt) self.nowGdate.set(gtm) self.LocalTime.set(ldt) self.LocalDate.set(ltm) self.after(100, self.gettime) #print (ltm) # Prove it is running this and the external code, too. pass root = tk.Tk() root.wm_title('Temp Converter') app = Application(master=root) w = 200 # width for the Tk root h = 125 # height for the Tk root # get display screen width and height ws = root.winfo_screenwidth() # width of the screen hs = root.winfo_screenheight() # height of the screen # calculate x and y coordinates for positioning the Tk root window #centered #x = (ws/2) - (w/2) #y = (hs/2) - (h/2) #right bottom corner (misfires in Win10 putting it too low. OK in Ubuntu) x = ws - w y = hs - h - 35 # -35 fixes it, more or less, for Win10 #set the dimensions of the screen and where it is placed root.geometry('%dx%d+%d+%d' % (w, h, x, y)) root.mainloop()
Comments