Tkinter:从画布删除图像时出错

时间:2019-01-13 12:04:00

标签: python multithreading animation tkinter web-scraping

我正在创建一个将Tkinter GUI与Web抓取相结合的应用程序。 “ searching_window”函数使用两个线程:一个用于较长的过程(Web爬网过程),另一个用于GUI。在GUI上,我使用画布和24帧gif模拟了GIF。我认为遇到的问题是,经过漫长的过程后,我删除了在画布中创建的所有图像,因为在删除它们时会出现24个不同的错误,即图像的确切数量。也许是因为我正在为Tkinter使用线程?但是,错误不会立即出现,我可以去使用下一个GUI窗口,并且在关闭每个Tkinter窗口之后,都会出现错误。

def prev_window():
    root = Tk()
    root.mainloop()

def next_window():
    root = Tk()
    root.mainloop()

def searching_window(settings):
    def long_process(settings):
        ...
    def app(settings):
        def event_gif(n=0):
            global timer_id
            gif = giflist[n%len(giflist)]
            canvas.create_image(gif.width()//2, gif.height()//2, image=gif)
            if t1.is_alive():
                timer_id = root.after(100, event_gif, n+1)
            else:
                canvas.delete(ALL)
                root.after_cancel(timer_id)
                canvas.place_forget()
                img_done.place(x=335, y=30)
                lbl_done.place(x=330, y=183)
                after = utils.number_html_files()
                lbl_found.configure(text="I found {} items.".format(after-before))
                lbl_found.place(x=217, y=205)

        def event_btn(event):
            if not t1.is_alive():
                root.destroy()
                if utils.number_html_files() != 0:
                    next_window()

        gifpath = datapath + "gif"
        _ = ["frame_{}.png".format(i) for i in range(1, 25)]
        imgfn = "checked.png"
        global timer_id
        timer_id = "after#0"
        before = utils.number_html_files()
        root = Tk()
        root.geometry("650x300+100+100")
        root.title("Searching...")

        font = Font(family="Times New Roman", size=15)
        font2 = Font(family="Times New Roman", size=12)
        background = Label(root, image=smallbackground)
        background.image = smallbackground


        __ = PhotoImage(file="{}{}".format(gifpath, _[0]))
        canvas = Canvas(root, width=300, height=198)

        giflist = []
        for img in _:
            photo = PhotoImage(file="{}{}".format(gifpath, img))
            giflist.append(photo)

        img_done = Label(root, image=imgfn)
        img_done.image = imgfn
        lbl_done = Label(root, text="Done!", font=font)
        lbl_found = Label(root, font=font, text="I found {} items.")
        btn_done = Button(root, text="Continue", font=font)
        btn_done.bind("<Button-1>", event_btn)

        background.place(x=-1, y=-1)
        canvas.place(x=258, y=30)
        btn_done.place(x=343, y=235)

        root.after(100, event_gif)

        root.mainloop()

    t1 = threading.Thread(target=long_process, args=[settings])
    t2 = threading.Thread(target=app, args=[settings])

    t2.start()
    t1.start()

    t2.join()
    t1.join()

以下是错误:

Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f0b8>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f0f0>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f128>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f160>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f198>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f1d0>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f208>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f240>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f278>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f2b0>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f2e8>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f320>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f358>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f390>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f3c8>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f400>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f438>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f470>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f4a8>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f4e0>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f518>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f550>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f588>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x7fc45c92f5c0>>
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3507, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Tcl_AsyncDelete: async handler deleted by the wrong thread

Process finished with exit code 134 (interrupted by signal 6: SIGABRT)

编辑:通过将根创建和主循环移动到定义线程的位置,并在创建新画布之前删除了最后一个画布图像,我修复了该错误:

def prev_window():
    root = Tk()
    root.mainloop()

def next_window():
    root = Tk()
    root.mainloop()

def searching_window(settings):
    def long_process(settings):
        ...
    def app(settings):
        def event_gif(n=0):
            global timer_id
            gif = giflist[n%len(giflist)]
            canvas.delete(ALL)
            canvas.create_image(gif.width()//2, gif.height()//2, image=gif)
            if t1.is_alive():
                timer_id = root.after(100, event_gif, n+1)
            else:
                canvas.delete(ALL)
                root.after_cancel(timer_id)
                canvas.place_forget()
                img_done.place(x=335, y=30)
                lbl_done.place(x=330, y=183)
                after = utils.number_html_files()
                lbl_found.configure(text="I found {} items.".format(after-before))
                lbl_found.place(x=217, y=205)

        def event_btn(event):
            if not t1.is_alive():
                root.destroy()
                if utils.number_html_files() != 0:
                    next_window()

        gifpath = datapath + "gif"
        _ = ["frame_{}.png".format(i) for i in range(1, 25)]
        imgfn = "checked.png"
        global timer_id
        timer_id = "after#0"
        before = utils.number_html_files()

        font = Font(family="Times New Roman", size=15)
        font2 = Font(family="Times New Roman", size=12)
        background = Label(root, image=smallbackground)
        background.image = smallbackground


        __ = PhotoImage(file="{}{}".format(gifpath, _[0]))
        canvas = Canvas(root, width=300, height=198)

        giflist = []
        for img in _:
            photo = PhotoImage(file="{}{}".format(gifpath, img))
            giflist.append(photo)

        img_done = Label(root, image=imgfn)
        img_done.image = imgfn
        lbl_done = Label(root, text="Done!", font=font)
        lbl_found = Label(root, font=font, text="I found {} items.")
        btn_done = Button(root, text="Continue", font=font)
        btn_done.bind("<Button-1>", event_btn)

        background.place(x=-1, y=-1)
        canvas.place(x=258, y=30)
        btn_done.place(x=343, y=235)

        root.after(100, event_gif)

    root = Tk()
    root.geometry("650x300+100+100")
    root.title("Searching...")
    t1 = threading.Thread(target=long_process, args=[settings])
    t2 = threading.Thread(target=app, args=[settings])

    t2.start()
    t1.start()

    root.mainloop()

    t2.join()
    t1.join()

0 个答案:

没有答案