time.sleep阻止按tkinter.Button

时间:2017-04-02 01:09:31

标签: python tkinter sleep

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

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()

1 个答案:

答案 0 :(得分:2)

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

使用通用窗口小部件方法after()无效。

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

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

而不是

time.sleep(1)

我发现了一些documentation