python - time.sleep 阻止按下 tkinter.Button

标签 python tkinter sleep

我正在尝试实现一个应用程序来显示图像 6 秒,然后使用单选按钮跳转到另一个页面,让他们评价自己对图像的感觉(给出 15 秒的评价),然后显示下一张图像。然而,为了倒计时15秒,我使用了time.sleep()函数,这使得程序按下单选按钮时非常慢(但我点击,按钮仍然可以按下)。我想知道是否有一种方法,可以让倒计时不影响程序,而只是让程序在时间到时跳到下一页。这是我的代码:

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.geometry('1800x970+15+5')
        self.title('Emotion Test')
        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, Show_image, Rate_e, EndPage):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")
    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()
        frame.execute()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text=instructions, width=1500, height=700, font=TITLE_FONT)
        label.pack(side="top")
        label.place(x=100, y=40, width=1500, height=700)
        button1 = tk.Button(self, text="Start", height = 5, width = 10,
                            command=lambda: controller.show_frame("Show_image"))
        button1.pack(side="bottom")

    def execute(self):
        current = -1

class EndPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text=instructions, width=1500, height=700,
        font=TITLE_FONT)
        label.pack(side="top")
        label.place(x=100, y=40, width=1500, height=700)

    def execute(self):
        current = -1

class Show_image(tk.Frame):

    def __init__(self, parent, controller):
        global seconds
        tk.Frame.__init__(self, parent)
        self.controller = controller
        global lbPic
        global timer1
        lbPic = tk.Label(self, text='Image System', width=1200, height=900)
        lbPic.place(x=20, y=50, width=1200, height=900)
        lbPic.pack(side="top", fill="both", expand=True)
        timer1 = tk.Label(self, text='timer', width=50, height=10)
        timer1.place(x=1325, y=2, width=50, height=10)
        timer1.pack(side="bottom", fill="both", expand=True)
    def execute(self):
        if (self.changePic(1)):
           for k in range(seconds, 0, -1):
               timer1["text"] = "Time left : " + str(k) + " s"
               self.update()
               time.sleep(1)
           self.controller.show_frame("Rate_e")
        else:
           self.controller.show_frame("EndPage")

    def changePic(self, flag):
        global current

        new = current + flag
        if new<0:
           #tkMessageBox.showerror('', 'last picture')
           return 0
        elif new>=len(pics):
             #tkMessageBox.showerror('', 'last picture')
             return 0
        else:
             #get the next picture
             pic = pics[new]
             im = Image.open(pic)
             w, h = im.size
             if w>1200:
                h = int(h*1200/w)
                w = 1200
             if h>800:
                w = int(w*800/h)
                h = 800
             im = im.resize((w,h))
             im1 = ImageTk.PhotoImage(im)
             lbPic['image'] = im1
             lbPic.image = im1
             current = new
             return 1

class Rate_e(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        global wait
        self.controller = controller
        global lbrate1
        global lbrate2
        global lbrate3
        global timer2
        lbrate1 = tk.Label(self, text='Pleasure', width=1400, height=260)
        lbrate1.place(x=50, y=10, width=1400, height=260)
        lbrate1.pack(side="top", fill="both", expand=True)
        lbrate2 = tk.Label(self, text='Excited', width=1400, height=260)
        lbrate2.place(x=50, y=230, width=1400, height=260)
        lbrate2.pack(side="top", fill="both", expand=True)
        lbrate3 = tk.Label(self, text='Controlled', width=1400, height=260)
        lbrate3.place(x=50, y=650, width=1400, height=260)
        lbrate3.pack(side="top", fill="both", expand=True)
        timer2 = tk.Label(self, text='timer', width=50, height=10)
        timer2.place(x=800, y=850, width=50, height=10)
        timer2.pack(side="bottom", fill="both", expand=True)

        MODES = [
            ("1", 1),
            ("2", 2),
            ("3", 3),
            ("4", 4),
            ("5", 5),
            ("6", 6),
            ("7", 7),
            ("8", 8),
            ("9", 9)
        ]
        global v1
        v1 = tk.StringVar()
        v1.set("score1") # initialize
        xaxis = 0
        for text, mode in MODES:
            b1 = tk.Radiobutton(self, text=text,
                        variable=v1, value=mode)
            b1.config(indicatoron=False,width=10,height=2)
            b1.place(x=140 + xaxis*127, y=240 , width=100, height=30)
            #b.pack(side="left")
            xaxis = xaxis + 1
        global v2
        v2 = tk.StringVar()
        v2.set("score2") # initialize
        xaxis = 0
        for text, mode in MODES:
            b2 = tk.Radiobutton(self, text=text,
                        variable=v2, value=mode)
            b2.config(indicatoron=False,width=10,height=2)
            b2.place(x=140 + xaxis*128, y=510 , width=100, height=30)
            #b.pack(side="left")
            xaxis = xaxis + 1
        global v3
        v3 = tk.StringVar()
        v3.set("score3") # initialize
        xaxis = 0
        for text, mode in MODES:
            b3 = tk.Radiobutton(self, text=text,
                        variable=v3, value=mode)
            b3.config(indicatoron=False,width=10,height=2)
            b3.place(x=140 + xaxis*125, y=800 , width=100, height=30)
            #b.pack(side="left")
            xaxis = xaxis + 1

    def execute(self):
        for k in range(wait, 0, -1):
            timer2["text"] = "Time left : " + str(k) + " s"
            self.update()
            time.sleep(1)
        Pleasure = v1.get()
        Excited = v2.get()
        Control = v3.get()
        print(Pleasure)
        print(Excited)
        print(Control)
        self.controller.show_frame("Show_image")

if __name__ == "__main__":
    suffix = ('.jpg', '.bmp', '.png')
    pics = [image_path + p for p in os.listdir(image_path) if p.endswith(suffix)]
    seconds = 2
    wait = 6
    current = -1
    app = SampleApp()
    app.mainloop()

最佳答案

tkinter 程序中使用 time.sleep() 会使其无响应,因为它会阻止 mainloop() 执行并能够响应事件。

要无效,请使用通用小部件方法 after()

因此,在您的情况下使用:

self.after(1000)  # 1000 ms = 1 sec

而不是

time.sleep(1)

这里有一些 documentation我发现了。

关于python - time.sleep 阻止按下 tkinter.Button,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43163631/

相关文章:

python - 在 Pandas 中创建日期范围的总和

python ImageTk.PhotoImage-段错误

python - TKinter tkFileDialog.askopenfilename 总是在其他窗口后面

javascript - 如何在javascript for循环中的每次迭代后延迟?

android - 如何防止 Android 应用程序锁定?

python - openpyxl 单元格样式未正确报告

python - 如何从二维numpy数组中选择样本?

python - 将 pandas 表导入 tkinter 项目

python - 后台运行 Python 脚本不断停止

python - 为什么Matlab和scikit-learn使用PLS回归时结果不同?