首页 > 解决方案 > 在 python 和 tkinter 中延迟 Entry textchanged 事件

问题描述

我的代码有问题,

我正在使用 python 和 tkinter 来开发我的程序,

但我有一个问题让我卡了一段时间,

我正在构建一个员工考勤应用程序,

员工有一个 ID,所以在我的应用程序中,员工在我的表单中的 textboxt 上输入他/她的 id

像这样 在此处输入图像描述

问题是,每个员工的 len(id) 介于 9 到 10 之间

所以我想我在 len(id) 输入为 9 之后创建了一个事件触发开始

ids = StringVar(value="")
ids.trace("w", lambda name, index, mode, ids=ids: textchanged(ids))
inputid = tkinter.Entry(window,font="Helvetica 20 bold",textvariable=ids)
inputid.pack()
inputid.place(relx=0.5,rely=0.187,width=300,height=30,anchor='sw',)
inputid.size()

def textchanged(ids):
id = ids.get()
if len(id) >= 9:
    time.sleep(3)
    print(id)
    compareimage(id)

问题是,文本框在文本框中输入 8 个字符 id 后停止输入,直到文本框中的 9 个长度 id 才能输入

但在我的控制台中它仍然可以打印 untul 9 lenght id

在此处输入图像描述

我该如何解决这个问题,

谁能帮帮我吗?

我将此代码添加到我的问题中

def compareimage(id):
    try:
        path = folder + id
        ClassNames = []
        mylist = os.listdir(path)
        for cls in mylist:
            curImg = cv2.imread(f'{path}/{cls}')
            image.append(curImg)
            ClassNames.append(os.path.splitext(cls)[0])
        encodeListKnown = finencode(image)
        print(encodeListKnown)
        print(ClassNames)
        print(mylist)
        time.sleep(3)
        while (True):
            ret, frames = cap.read()
            frames =cv2.flip(frames,1)
            gray = cv2.cvtColor(frames, cv2.COLOR_BGR2RGB)
            imgS = cv2.resize(frames, (0, 0), None, 0.25, 0.25)
            imgS = cv2.resize(frames, (0, 0), None, 0.25, 0.25)
            imgS = cv2.cvtColor(imgS, cv2.COLOR_BGR2RGB)
            facecurentframe = face_recognition.face_locations(imgS)
            encodecurframe = face_recognition.face_encodings(imgS, facecurentframe)
            encodelistface = []
            for faceloc in zip(encodecurframe, facecurentframe):
                encodeface = faceloc[0]
                encodelistface.append(encodeface)
            matches = face_recognition.compare_faces(encodeListKnown, encodelistface[0])
            facedistance = face_recognition.face_distance(encodeListKnown, encodelistface[0])
            print(encodelistface)
            print(facedistance)
            print(matches)
            a = str(matches)
            print(bool(matches))
            if (bool(matches) == True):
                print("True")
                now = datetime.now()
                stringnow = now.strftime('%y/%m/%d %H:%M:%S.%f')
                f = open(foldertxt, "a")
                logabsen = id + " , "+ stringnow  + "\n"
                f.write(logabsen )
                playsound(folderaudio)
                encodelistface.clear()
                encodeListKnown.clear()
                image.clear()
                ClassNames.clear()
                inputid.delete(0,END)
                break
            else:
                print("False")
                encodelistface.clear()
                encodeListKnown.clear()
                image.clear()
                ClassNames.clear()
                inputid.delete(0,END)
                break
    except :
        print("There is An Exception" , sys.exc_info()[0])

标签: pythontkinter

解决方案


每当更新时,您都可以使用它after()来安排超时任务。您需要在条形码扫描仪的inputid每次更新之间选择一个足够长的超时时间。inputid如果inputid在计划的超时时间之前再次更新,则需要取消之前的超时任务并重新安排另一个任务。

如果触发了超时任务,可以在超时回调中进行人脸识别,但建议使用线程来完成,因为这可能是一个耗时的任务,会阻塞tkinter主循环。

下面是一个例子:

import tkinter as tk
import random
import threading
import time

def compareimage(id):
    face.config(text='Checking ...', image=tk.PhotoImage())
    face.update_idletasks()
    # simulate the face recognition task
    time.sleep(5)
    # show the result image
    face.image = tk.PhotoImage(file='result.png')
    face.config(text=id, image=face.image)
    ids.set('')

def text_completed(ids):
    print('timed out')
    id = ids.get()
    if len(id) > 8:
        print('id:', id)
        threading.Thread(target=compareimage, args=(id,), daemon=True).start()

def text_changed(ids):
    global timeout_id
    if timeout_id:
        # cancel previous scheduled task
        root.after_cancel(timeout_id)
    if len(ids.get()) > 0:
        # schedule a timeout task, adjust the delay to suit your real situation
        timeout_id = root.after(1000, text_completed, ids)

# simulate barcode reader input
def scan_id(n=10):
    if n > 0:
        inputid.insert('end', random.choice('1234567890'))
        inputid.after(50, scan_id, n-1)

timeout_id = None

root = tk.Tk()

tk.Label(root, text='Employee Attandance', font='Helvetica 32 bold').pack()

ids = tk.StringVar(value='')
ids.trace('w', lambda *args: text_changed(ids))

inputid = tk.Entry(root, font='Helvetica 20 bold', textvariable=ids, width=12)
inputid.pack()

face = tk.Label(root, text='', image=tk.PhotoImage(), compound='top', width=600, height=400)
face.pack()

tk.Button(root, text='Scan ID', command=lambda: scan_id(random.randrange(9,11))).pack()

root.mainloop()

请注意,该按钮Scan ID是模拟条形码阅读器。


推荐阅读