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

StackOverflow https://stackoverflow.com/questions/459083

  •  19-08-2019
  •  | 
  •  

문제

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

그러나 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."""

다른 팁

그만큼 솔루션은 Bjorn에 의해 게시되었습니다 내 컴퓨터에서 "runtimeerror : 다른 아파트에서 TCL 호출"메시지가 나타납니다 (Redhat Enterprise 5, Python 2.6.1). Bjorn 은이 메시지를받지 못했을 수도 있습니다. 내가 확인한 한 곳, Tkinter를 사용한 Mishandling Threading은 예측할 수없고 플랫폼 의존적입니다.

문제는 그 것 같습니다 app.start() 앱에는 TK 요소가 포함되어 있기 때문에 TK에 대한 참조로 계산됩니다. 교체하여 이것을 고쳤습니다 app.start() a 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)

시뮬레이션에서와 같이 자신의 루프를 작성할 때 (나는 가정) 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')

그래도 멀티 스레드 프로그래밍은 어렵고 발에서 자신을 쏘는 것은 정말 쉽습니다. 예를 들어, 위의 샘플 클래스의 멤버 변수를 변경할 때는 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()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top