【问题标题】:Countdown timer not updating in tkinter倒计时计时器未在 tkinter 中更新
【发布时间】:2020-09-28 05:01:35
【问题描述】:

我正在尝试使用 python 和 tkinter 创建一个支付应用程序。有一个“主”程序从用户那里获取卡号、cvv 等详细信息并将其发送到另一个程序,即支付网关。

因此不是真正的支付网关。它只是用数据库交叉检查卡号、cvv 等。

我没有在我的代码中包含主程序,因为我可以向您保证,我已经检查了值是否已成功地从主程序传输,并且确实如此。

下面的程序有点长,抱歉,我会尽量集中解决这个问题。

这里是“支付网关”:

import smtplib, ssl
from tkinter import*
from tkinter import messagebox
import mysql.connector as mc
from random import randint
import time
global root

def visa_card_payment(cardnumber, cvv, name, expiry, premium, product):
    global root  

mycon=mc.connect(host="localhost",user="root",passwd="1234",database="visa",charset='utf8')
cursor=mycon.cursor()

todo1="select registered_email from all_data where card_no=%s and cvv='%s' and expiry='%s'"%(cardnumber,cvv,expiry)

cursor.execute(todo1)
data=cursor.fetchall()

if cursor.rowcount==1:
    
    cursor.execute(todo1)
    data=cursor.fetchone()
    print(data[0])
    emailid=data[0]
    
    def countdown(t):

        global root


        def payu(entered_otp):
            global root
            global otp
            global status
            global attempts

            if otp==entered_otp:

                status="true"

                root.destroy()
                root=Tk()
                root.title("Payment Successful")
                root.geometry("200x200")

                succ_label=Label("Payment Successful")
                succ_label.pack()

            elif otp!=entered_otp:
                if attempts!=3:
                    messagebox.showwarning(root,"Incorrect OTP. You have %s tries left."%(3-attempts))
                    attempts=+1

                elif attempts==3:
                    messagebox.showwarning(root,"Authentication Failed")
                    root.destroy()

        global root                    
        global attempts
        global status
        global otp

        attempts=1
        otp=randint(99999,1000000)
        status="false"

        port = 465
        smtp_server = "smtp.gmail.com"
        sender_email = "visaandezpay@gmail.com"
        receiver_email =str(emailid)
        password = "visaandezpay2003"
        message = """\Subject:

        To %s,
        Dear Visa Cardholder,
        Your One Time Password (OTP) for payment to Tirth Insurance 4 Life towards payment of '%s' for policy '%s' is: %s
        Your OTP will be active for 5 minutes.
        Please do not share this OTP with anyone else."""%(name,premium,product,otp)

        context = ssl.create_default_context()
        with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
            server.login(sender_email, password)
            server.sendmail(sender_email, receiver_email, message)
        
        root=Tk()
        root.title("EzPay Payment Gateway")
        root.geometry("200x200")
        otp_label=Label(root,text="Enter OTP:")
        otp_entry=Entry(root,width=30,borderwidth=3)
        otp_entry.insert(0,0)
        countdown_label1=Label(root,text="OTP active for:")
        countdown_label2=Label(root,text="05:00")
        submit_button=Button(root,text="Submit",command=lambda:payu(int(otp_entry.get())))

        otp_label.grid(row=0,column=0)
        otp_entry.grid(row=0,column=1)
        countdown_label1.grid(row=1,column=0)
        countdown_label2.grid(row=1,column=1)
        submit_button.grid(row=2,column=1)
        
        root.mainloop()
        
        while t:
            
            mins, secs = divmod(t, 60)
            timeformat='{:02d}:{:02d}'.format(mins, secs)
            countdown_label2.grid_forget()
            countdown_label2=Label(root,text=timeformat)
            countdown_label2.grid(row=1,column=1)
            time.sleep(1)
            t=-1
        if status=="true":
            pass

        elif status=="false":
            
            otp=1000000
            messagebox.showwarning(root,"Authentication Failed")
            root.destroy()
        
    
    countdown(300)

主程序导入该程序并运行visa_card_payment函数并提供所需的值。

开始,程序运行查询,查看行数是否为 1,获取所需的电子邮件 ID,并输入 t=300 的倒计时(t)

然后它生成一个随机 otp,为此发送一封电子邮件,并创建一个新窗口,要求用户输入 otp。这就是麻烦的开始。

我有一个 countdown_label2 最初有 5:00 有文本。然后我有一个 while(t) 函数可以倒计时 5 分钟。

每过一秒,它就必须忘记前一个 countdown_label2 的位置,创建一个新标签,其文本比该标签少一秒,然后重新放回原处。

程序会运行5分钟,如果输入正确的otp并提交,则显示成功,否则重复两次尝试,倒计时内也是如此

邮件接收成功,但是countdown_label2没有更新,一直停留在5:00。

我以为问题出在我放置root.mainloop()的地方,但是我把它放在上面代码中的地方只能工作,否则不会出现otp屏幕。

这是 otp 屏幕:

如果我单击提交,则会出现一个新窗口,其中包含给定的 root.title(),但其中没有出现任何内容(我有一个 succ_label,但没有出现)。

如果我关闭屏幕,则会出现以下内容:

我真的很抱歉浪费你的时间阅读这么多的小任务,但所有的帮助将不胜感激。

谢谢!

PS:def visa_card_payment 函数下的所有内容都必须缩进。

【问题讨论】:

  • 为什么没人接听?
  • 我只能建议你为你的问题做一个更简单的例子。现在您的代码包含 f.ex。电子邮件发送,这与您的问题无关,对吧?
  • 是的,我不这样做

标签: python tkinter


【解决方案1】:

这里违反了一些基本的 Tkinter 规则。

  1. tkinter Tk 根方法永远不会超过一个(它们不会很好地共存)
  2. 切勿使用无限 while 循环(它们会阻止 gui 更新)

要解决 1 对任何子窗口使用 Toplevel 而不是 Tk

求解 2 有点复杂

包含倒计时的 while 循环不会被执行,因为 root.mainloop() 将 继续运行直到 GUI 关闭。

您应该考虑将倒数计时器放在一个单独的函数中,该函数每秒由 tkinter .after 方法调用一次。

当按钮被按下时,你会在一秒钟后调用类似这样的函数来调用函数。

root.after(1000, myCountdownFunction)

那么你的函数看起来像

def myCountDownFunction():
    mins, secs = divmod(t, 60)
    timeformat='{:02d}:{:02d}'.format(mins, secs)
    countdown_label2.grid_forget()
    countdown_label2=Label(root,text=timeformat)
    countdown_label2.grid(row=1,column=1)
    t=-1
    root.after(1000, MyCountdownFunction) # Calls this function again in 1 second

这个问题非常广泛,我怀疑任何答案都能够完全解决您的问题,而无需完全重写代码。

【讨论】:

  • 感谢您抽出宝贵时间回答这个问题。它现在完美运行?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
相关资源
最近更新 更多