0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

tkinter [image "pyimage1" doesn't exist]エラー解決備忘録

Posted at

はじめに

customtkinter(tkinterのモダンUI版、実装方法はtkinterとほぼ同じ)で発生した以下エラーの解決方法を備忘録として残します。
_tkinter.TclError: image "pyimage1" doesn't exist
こちらのエラーは1つのアプリケーションの中で2つのウィンドウを作成した際に発生したものです。

現象の再現と処理の流れ

以下実際のプログラムを簡単化して同じエラーとなるようにしたプログラムです。

処理の流れ

  1. Contrelloeから、1つ目のウィンドウをとなるView1を実行、mainloop()します。
  2. View1のウィンドウであるボタンを押すともう1つのウィンドウとなるView2が立ち上がり、こちらも同様にmainloop()します。
  3. View2のウィンドウでまた別のボタンを押すと画像が表示される想定でしたが、画像が表示されずに該当エラーが発生しました。
import customtkinter
import tkinter as tk
from PIL import Image, ImageTk

class Controller:
    def __init__(self):
        self.view1 = View1(self)
        self.view1.mainloop()
        
    def add_window(self):        
        self.view2 = View2(self)
        self.view2.mainloop()
    
    def display_img(self):
        img = Image.open("dog1.jpg")
        img = ImageTk.PhotoImage(img)
        self.view2.add_img(img)

    
class View1(customtkinter.CTk):
    def __init__(self, controller):
        super().__init__()
        self.geometry("300x300")
        self.controller = controller
        customtkinter.CTkButton(self, text="view2ウィンドウに画像を表示",
                                command=self.controller.add_window).pack()


class View2(customtkinter.CTk):
    def __init__(self, controller):
        super().__init__()
        self.geometry("500x500")
        self.controller = controller
        customtkinter.CTkButton(self, text="画像を表示します", command=self.controller.display_img).pack()
        
    def add_img(self, img):
        self.image_label = customtkinter.CTkLabel(self, image=img)
        self.image_label.image = img
        self.image_label.pack()


if __name__ == "__main__":
    controller = Controller()

原因

今回の原因は2つViewをそれぞれmainloop()していたことでした。
それによって連携させたいウィンドウが独立してしまい、画像オブジェクトの参照が無効になっていたと推察されます。

対処法

  • 各ウィンドウでmainloop()を呼び出さないようにして、View1mainloop()で全体を制御
  • View2Toplevelを使用したサブウィンドウとして機能させる
    具体的にはサブウィンドウとしたいクラスにToplevelクラスを継承させてあげます

対処コード

# 2つめのmianloop()を削除(コメントアウト化)
# self.view2.mainloop()

# class View2(customtkinter.CTk):  ⇚これを削除、代わりにToplevelクラスを継承
class View2(customtkinter.CTkToplevel):

最終的なコード

import customtkinter
import tkinter as tk
from PIL import Image, ImageTk

class Controller:
    def __init__(self):
        self.view1 = View1(self)
        self.view1.mainloop()
        
    def add_window(self):        
        self.view2 = View2(self)
        # self.view2.mainloop()
    
    def display_img(self):
        img = Image.open("dog1.jpg")
        img = ImageTk.PhotoImage(img)
        self.view2.add_img(img)

    
class View1(customtkinter.CTk):
    def __init__(self, controller):
        super().__init__()
        self.geometry("300x300")
        self.controller = controller
        customtkinter.CTkButton(self, text="view2ウィンドウに画像を表示",
                                command=self.controller.add_window).pack()


class View2(customtkinter.CTkToplevel):
    def __init__(self, controller):
        super().__init__()
        self.geometry("500x500")
        self.controller = controller
        customtkinter.CTkButton(self, text="画像を表示します", command=self.controller.display_img).pack()
        
    def add_img(self, img):
        self.image_label = customtkinter.CTkLabel(self, image=img)
        self.image_label.image = img  # Keep a reference to the image
        self.image_label.pack()


if __name__ == "__main__":
    controller = Controller()

修正後実行結果

image.png

まとめ

  • mainloop()はアプリケーションで1回だけでそれ以上はNG
  • 複数ウィンドウはToplevelを使用してサブウィンドウ化して対応
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?