建议:在 tkinter 中启动递归函数

Recommendation: Starting a recursion function in tkinter

我这个程序的目标是创建一个 Tweepy 流,使用 tkinter 将 Tweets 汇集到一个演示风格的 GUI 中。此外,该演示文稿不断地 运行 直到我打破了通过推文循环的代码。在我的 GUI 中,我有一个函数 change(n) 可以有效地改变推文幻灯片,如果你想那样想的话。

我正在寻找有关从何处开始此循环功能的建议。由于我 运行 宁在 tkinter,我需要在 root.mainloop() 之前完成它。但是,如果我在 __init__initui() 期间调用,它将永远不会到达 root.mainloop(),因为它会在调用应用程序实例后触发。

代码如下:

from tweepy.streaming import StreamListener
from tweepy import OAuthHandler
from tweepy import Stream
from tkinter import *
from PIL import Image, ImageTk
from time import sleep

class listener(StreamListener):
    def __init__(self, application):
        self.application = application

    def on_data(self, data):
        self.application.add(data)

    def on_error(self, status):
        print(status)

class app(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent, bg="white")
        self.parent = parent

        global screen_h, screen_w
        screen_h = self.parent.winfo_screenheight()
        screen_w = self.parent.winfo_screenwidth()

        global tweets
        tweets = ["Tweet with #2017"]

        self.parent.bind('<Escape><Escape>', self.close)
        self.initui()


    def initui(self):
        self.parent.title("2017")
        self.pack(fill=BOTH, expand=1)

        t = Image.open("twitter.jpg")
        t_ar = t.size[0]/t.size[1]
        t_h = int(screen_h*.1)
        t_w = int(t_h * t_ar)
        t = t.resize((t_w,t_h),Image.ANTIALIAS)
        t = ImageTk.PhotoImage(t)

        logo = Label(self, image=t, bd=0, highlightthickness=0)
        logo.image = t
        position = ((screen_w*.1)-(t_w/2),(screen_h*.5)-(t_h/2))
        logo.place(x=position[0], y=position[1])


    def add(self, tweet):
        tweets.append(tweet)

    def change(self, n):
        tweet = tweets[n]
        label = Label(self, text=tweet, height=screen_h, width=int(screen_w*.75), anchor=CENTER, bg="white", font=("Helvetica", 24))
        label.pack(side=RIGHT)
        sleep(30)
        if n+2 <= len(tweets):
            label.destroy()
            self.change(n+1)
        else:
            label.destroy()
            self.change(0)

    def close(self, event):
        self.parent.destroy()


def run():
    #start the app
    root = Tk()
    root.attributes("-fullscreen", True)
    start = app(root)

    #Twitter API keys
    consumer_key=""
    consumer_secret=""
    access_token=""
    access_token_secret=""

    #Start Twitter Stream
    l = listener(start)
    auth = OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_token_secret)
    stream = Stream(auth, l)
    stream.filter(track=['basketball'], async=True)

    root.mainloop()

run()

我无法测试您的代码,但您可以在不使用递归且不使用 sleep(30) 的情况下执行此操作,但使用 after(miliseconds, function_name, argument) - 如下所示:

def __init__(self, parent):

    # create empty label only once
    self.label = Label(self, height=screen_h, width=int(screen_w*.75), anchor=CENTER, bg="white", font=("Helvetica", 24))
    self.label.pack(side=RIGHT)

def change(self, n):

    # change only text
    self.label['text'] = tweets[n]

    n += 1

    if n == len(tweets):
        n = 0

    # or in one line
    # n = (n + 1) % len(tweets)

    # run again after 30000ms = 30s
    root.after(30000, self.change, n)
    #self.parent.after(30000, self.change, n)

现在您可以在 mainloop() 之前启动它并且它不会冻结 Tkinter 因为 after 将它发送到 mainloop() 之后会调用 change() 30s.