Programming

Tkinter의 이벤트 루프와 함께 자신의 코드를 어떻게 실행합니까?

procodes 2020. 8. 3. 17:58
반응형

Tkinter의 이벤트 루프와 함께 자신의 코드를 어떻게 실행합니까?


남동생이 방금 프로그래밍에 참여하고 있으며 과학 박람회 프로젝트를 위해 하늘에있는 새 떼를 시뮬레이션하고 있습니다. 그는 대부분의 코드를 작성했으며 잘 작동하지만 새는 매 순간 움직여야 합니다 .

그러나 Tkinter는 자체 이벤트 루프의 시간을 낭비하기 때문에 코드가 실행되지 않습니다. 이렇게 root.mainloop()실행, 실행을, 그리고 것은 실행 유지하고, 그것을 실행하는 유일한 방법은 이벤트 핸들러입니다.

그의 코드를 메인 루프와 함께 실행하는 방법이 있습니까 (멀티 스레딩없이 혼란스럽고 간단하게 유지해야 함) 그렇다면 그렇다면 무엇입니까?

지금 그는 추악한 해킹을 시도하여 자신의 move()기능을에 연결했습니다 <b1-motion>. 버튼을 누른 상태에서 마우스를 움직이면 작동합니다. 그러나 더 좋은 방법이 있어야합니다.


객체 에서 after메소드를 사용하십시오 Tk.

from tkinter import *

root = Tk()

def task():
    print("hello")
    root.after(2000, task)  # reschedule event in 2 seconds

root.after(2000, task)
root.mainloop()

after메소드에 대한 선언 및 문서는 다음과 같습니다 .

def after(self, ms, func=None, *args):
    """Call function once after given time.

    MS specifies the time in milliseconds. FUNC gives the
    function which shall be called. Additional parameters
    are given as parameters to the function call.  Return
    identifier to cancel scheduling with after_cancel."""

비요른에 의해 게시 솔루션 A의 결과 "RuntimeError에 : 다른 아파트에서 Tcl의 호출"메시지가 내 컴퓨터에 (레드햇 엔터프라이즈 5, 파이썬 2.6.1). 내가 확인한 한 장소 에 따르면 Tkinter로 스레딩을 잘못 처리하는 것은 예측할 수 없으며 플랫폼에 따라 다르 므로 Bjorn 은이 메시지를 얻지 못했을 수 있습니다 .

app.start()응용 프로그램에 Tk 요소가 포함되어 있기 때문에 문제는 Tk에 대한 참조로 계산됩니다. I는 교체하여 고정 app.start()로모그래퍼 self.start()내부 __init__. 또한 모든 TK에 참조가 내부에 하나가되도록 만들었 호출하는 기능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)

When writing your own loop, as in the simulation (I assume), you need to call the update function which does what the mainloop does: updates the window with your changes, but you do it in your loop.

def task():
   # do something
   root.update()

while 1:
   task()  

Another option is to let tkinter execute on a separate thread. One way of doing it is like this:

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

Be careful though, multithreaded programming is hard and it is really easy to shoot your self in the foot. For example you have to be careful when you change member variables of the sample class above so you don't interrupt with the event loop of Tkinter.


This is the first working version of what will be a GPS reader and data presenter. tkinter is a very fragile thing with way too few error messages. It does not put stuff up and does not tell why much of the time. Very difficult coming from a good WYSIWYG form developer. Anyway, this runs a small routine 10 times a second and presents the information on a form. Took a while to make it happen. When I tried a timer value of 0, the form never came up. My head now hurts! 10 or more times per second is good enough for me. I hope it helps someone else. Mike Morrow

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

참고URL : https://stackoverflow.com/questions/459083/how-do-you-run-your-own-code-alongside-tkinters-event-loop

반응형