Frage

Mein kleiner Bruder ist gerade erst in der Programmierung und für sein Projekt Science Fair, hat er in dem Himmel eine Simulation einer Herde von Vögeln zu tun. Er meisten seinen Code bekommen geschrieben, und es funktioniert gut, aber die Vögel müssen sich bewegen jeder Augenblick .

Tkinter jedoch Schweine, die Zeit für die eigene Ereignisschleife, und so wird sein Code nicht ausgeführt werden. Doing root.mainloop() läuft, läuft und läuft weiter, und das einzige, was es läuft, ist die Ereignishandler.

Gibt es eine Möglichkeit, seinen Code neben dem mainloop laufen zu haben (ohne Multithreading, es ist verwirrend, und dies sollte einfach gehalten werden), und wenn ja, was ist das?

Im Augenblick kam er mit einem hässlichen zerhacken, bindet seine move() Funktion <b1-motion>, so dass, solange er den Knopf gedrückt hält und wackelt mit der Maus, es funktioniert. Aber es muss ein besserer Weg sein.

War es hilfreich?

Lösung

Mit der after Methode auf dem Tk Objekt:

from tkinter import *

root = Tk()

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

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

Hier ist die Deklaration und Dokumentation für die after Methode:

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."""

Andere Tipps

Die Lösung von Bjorn Ergebnissen in einem geschrieben „Runtime: Aufruf Tcl aus verschiedener Wohnung“ Nachricht auf meinem Computer (RedHat Enterprise 5, python 2.6.1). Bjorn haben könnte diese Nachricht nicht erhalten, da nach geprüft , ist falsche Handhabung Einfädeln mit Tkinter unberechenbar und plattformabhängig.

Das Problem scheint, dass app.start() zählt als Verweis auf Tk zu sein, da App Tk Elemente enthält. Ich reparierte diese durch app.start() mit einem self.start() innen __init__ ersetzen. Ich habe es auch so, dass alle Tk Referenzen sind entweder innerhalb der Funktion, die mainloop() ruft oder ist innerhalb von Funktionen, die von heißen die Funktion, die mainloop() nennt (dies offenbar kritisch zu vermeiden, dass die "andere Wohnung" Fehler).

Schließlich habe ich ein Protokoll-Handler mit einem Rückruf, da ohne diese das Programm mit einem Fehler beendet, wenn die Tk-Fenster durch den Benutzer geschlossen wird.

Der überarbeitete Code lautet wie folgt:

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

Wenn Sie Ihre eigene Schleife zu schreiben, wie es in der Simulation (ich nehme an), müssen Sie die update Funktion aufrufen, die tut, was der mainloop tut: aktualisiert das Fenster mit den Änderungen, aber Sie tun es in der Schleife

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

while 1:
   task()  

Eine weitere Option ist tkinter auf einem separaten Thread ausführen zu lassen. Eine Möglichkeit, es zu tun, ist wie folgt:

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

obwohl Vorsicht, Multithread-Programmierung ist hart und es ist wirklich einfach, um sich selbst in den Fuß zu schießen. Zum Beispiel muss man vorsichtig sein, wenn Sie Elementvariablen der Beispielklasse ändern oben, so dass Sie nicht unterbrechen mit der Ereignisschleife von Tkinter.

Dies ist die erste funktionierende Version von dem, was ein GPS-Leser und Daten Präsentator sein. tkinter ist eine sehr fragile Sache mit viel zu wenigen Fehlermeldungen. Dabei spielt es keine Sachen setzen und sagt nicht, warum ein Großteil der Zeit. Sehr schwer kommt von einem guten WYSIWYG Form Entwicklern. Wie auch immer, diese läuft eine kleine Routine 10 mal pro Sekunde und stellt die Informationen in einem Formular. Es dauerte eine Weile, um sie zu geschehen. Wenn ich einen Timer-Wert von 0 versucht, kam die Form nie auf. Mein Kopf tut weh, jetzt! 10 oder mehr Mal pro Sekunde ist genug für mich gut. Ich hoffe, dass es jemand anderes hilft. 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()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top