【问题标题】:Threads And Time + Tkinter In PythonPython 中的线程和时间 + Tkinter
【发布时间】:2017-06-12 11:51:33
【问题描述】:

在 tkinter 中,我制作了一个密码 GUI,有些人用它帮助我处理了其他事情。问题是:我制作了一个名为timeload的文件,其中有一个while 循环。当我将它导入我的程序时,它会卡在import上,因为timeload内部有循环。我认为有一种方法可以用线程来实现,但我不知道如何在我的代码中实现它。以下是主要代码:

import tkinter as tk
from threading import Thread
import timeload


class FirstFrame(tk.Frame):
    trys = 3
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.pack()
        master.title("Enter password")
        master.geometry("300x300")
        self.clock = tk.Label(self, fg='blue')
        self.clock.config(text=self.timeload.timeset())
        self.clock.pack()
        self.status2 = tk.Label(self, fg='blue')
        self.status2.pack()
        self.status = tk.Label(self, fg='red')
        self.status.pack()
        self.number = tk.Label(self, fg='red')
        self.number.pack()
        self.trysremain = tk.Label(self, fg='red')
        self.trysremain.pack()
        self.userlbl = tk.Label(self, text='Enter Username')
        self.userlbl.pack()
        self.userE = tk.Entry(self)
        self.userE.pack()
        self.userE.focus()
        self.lbl = tk.Label(self, text='Enter Password')
        self.lbl.pack()
        self.pwd = tk.Entry(self, show="*") 
        self.pwd.pack()
        self.pwd.bind('<Return>', self.check)
        self.btn = tk.Button(self, text="Done", command=self.check)
        self.btn.pack()
        self.btn = tk.Button(self, text="Cancel", command=self.quit)
        self.btn.pack()

    def check(self, event=None):

        if self.pwd.get() == app.password:
            if self.userE.get() == app.user:
                 self.destroy()
                 self.app= SecondFrame(self.master)
            else:
                self.status2.config(text="Wrong Username")

        else:
            self.trys = self.trys - 1
            self.status.config(text="Wrong password")
            self.number.config(text=self.trys)
            self.trysremain.config(text="Trys remaining")
           if self.trys == 0:
                root.destroy()
                root.quit()


class SecondFrame(tk.Frame):
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.pack()
        master.title("Main Application")
        master.geometry("600x400")
        self.c = tk.Button(self, text="Options", command=self.third_frame_open)
        self.c.pack()

    def third_frame_open(self):
        self.destroy()
        self.app= ThirdFrame(self.master)


class ThirdFrame(tk.Frame):
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.pack()
        self.password_set = tk.Label(self, fg='green')
        self.password_set.pack()
        master.title("Options")
        master.geometry("400x300")
        self.but2 = tk.Button(self, text="Go Back",     command=self.second_frame_open)
        self.but2.pack()
        self.but1 = tk.Button(self, text="Change password", command=self.showpasswordinput)
        self.but1.pack()
        self.but1.bind('<Return>', self.showpasswordinput)

    def showpasswordinput(self):
        self.but1.pack_forget()
        self.e = tk.Entry(self.master, show="*")
        self.e.pack()
        self.e.focus()
        self.but2 = tk.Button(self, text="Change password", command=self.set_password)
       self.but2.pack()
        self.but2.bind('<Return>', self.set_password)

    def set_password(self):
        self.password_set.config(text="Password Updated")
        setpass = open("password_store.txt", "w")
        passvar = self.e.get()
        self.e.pack_forget()
        setpass.write(passvar)
        setpass.close()

    def second_frame_open(self):
        self.destroy()
        self.app= SecondFrame(self.master)

if __name__=="__main__":
    root = tk.Tk()
    app=FirstFrame(root)
    user = open("user_store.txt", "r")
    app.user = user.read()
    user.close()
    password2 = open("password_store.txt", "r")
    app.password = password2.read()
    password2.close()
    root.mainloop()

这是timeload中的代码:

import datetime
timeload = ('on')
while timeload == ('on'):
    timeset = datetime.datetime.now()

谢谢, 杰克

【问题讨论】:

  • while timeload == ('on'): timeset = datetime.datetime.now() 包装在函数中,您可以在需要时调用它。
  • @Zydnar 如果你把它作为答案,我可以接受它作为答案
  • 为什么要导入这个文件?除了锁定程序之外,它绝对没有任何用处。您真正想通过导入此文件来完成什么?
  • 没错,Tkinter 在一个循环中运行自身,所以这个解决方案很尴尬,并且可能你会有很多没有中断条件的 while 循环 - 真的 baaaad。
  • 你真正想要达到什么目的? @Zyndar 的回答只会让你陷入函数内部的循环中。如果您尝试定期更新 GUI 上显示的时间,请使用 .after 方法定期调用函数并将标签设置为当前时间。无需导入,无需循环。

标签: python multithreading python-3.x tkinter tk


【解决方案1】:

您不应该在 tkinter 中使用长循环或无限循环,它们会阻止 GUI 响应用户操作。 定期更新时间等字段的正确方法是使用 tkinter .after 方法。

请参阅下面的基本程序示例,其中标签每 1 秒更新一次当前时间。

try:
    import tkinter as tk
except:
    import Tkinter as tk

import datetime

class App(tk.Frame):
    def __init__(self,master=None,**kw):
        #Create the widgets
        tk.Frame.__init__(self,master=master,**kw)
        self.timeStr = tk.StringVar()
        self.lblTime = tk.Label(self,textvariable=self.timeStr)
        self.lblTime.grid()
        #Call the update function/method to update with current time.
        self.update()

    def update(self):
        self.timeStr.set(datetime.datetime.now())
        ## Now use the .after method to call this function again in 1sec.
        self.after(1000,self.update)


if __name__ == '__main__':
    root = tk.Tk()
    App(root).grid()
    root.mainloop()

【讨论】:

  • 这似乎可以工作,但它给了我一个错误:
  • Traceback(最近一次调用最后):文件“D:\Tkinter_Final\Secure\Password_Final.py”,第 115 行,在 app=FirstFrame(root) 文件“D:\Tkinter_Final\ Secure\Password_Final.py",第 16 行,在 init self.clock.config(self,textvariable=self.timecall()) TypeError: 'StringVar' object is not callable
  • 表示StringVar不可调用
  • 看我给你的代码。 tk.Label(self,textvariable=self.timeStr),在self.timeStr之后没有()
  • 制作什么单独的文件?您可以将整个 App 类放在一个单独的文件中并导入它。我建议您将其重命名为 GUIClock 或类似名称,然后在您的主程序中使用 clock = GUIClock(root) 创建它的实例
猜你喜欢
  • 2022-01-01
  • 1970-01-01
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多