59553


Tkを使用して、Imageファイルを描画しているのですが、部分テストのために、一部のダイアログのみ描画配置などを確認するため、ソースコードを一部流用していました。  
今まで動作していた以下の関数からエラーが発生しました。

[code]

        def LoadImage(self):
            self.img_single = self._chk_image_file_(".\\icon\\mon_s.gif")
    
            self.img_single = ImageTk.PhotoImage(self.img_single)
    
            return
    
[/code]

エラーの内容

[code]

    RuntimeError: Too early to create image
    Exception ignored in: <bound method PhotoImage.__del__ of <PIL.ImageTk.PhotoImage object at 0x0000029C4F87A9E8>>
    Traceback (most recent call last):
      File "C:\Program Files (x86)\Microsoft Visual Studio\Shared\Anaconda3_64\lib\site-packages\PIL\ImageTk.py", line 123, in __del__
        name = self.__photo.name
    AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
    
[/code]

全ソースコード

[code]

    #! /usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import tkinter as tk
    from tkinter import ttk
    from PIL import Image,ImageTk,ImageDraw
    
    
    class class_Pattern_main(object):    
        def __init__(self):
    
            self.screen_w = 300
            self.screen_h = 200
            self.dlg_pos_x = 10
            self.dlg_pos_y = 10
            self.dlg_pad = 4
    
            self.sticky = tk.N+tk.S+tk.E+tk.W
    
            self.LoadImage()
    
    
        def createMainWindow(self):
    
            obj = ttk.tkinter.Tk() 
    
            geo_string = str(self.screen_w) + "x" + str(self.screen_h) + "+" + str(self.dlg_pos_x)  + "+" + str(self.dlg_pos_y) 
    
            obj.geometry(geo_string) 
    
            return obj
    
        def _chk_image_file_(self,f_path):
            try:
                # ファイルを読み込んで64x64にリサイズ
                ret_obj = Image.open(f_path).resize((64,64))
            except IOError:
                #Logに残すとか
                msg_text = "{0}{1}{2}".format(self.log_header,"指定されたアイコンファイルが読み込めません。" ,f_path)
    
                # 代わりとなるイメージを作成して返す。
                ret_obj = Image.new('RGB',(64,64),(150,150,150))
                draw = ImageDraw.ImageDraw(ret_obj)
                draw.rectangle((4,4,60,60), fill = None, outline = (250,30,30),width=2)
                draw.line((60,4,4,60), fill = (250,30,30),width=2)
    
            return ret_obj           
    
        def LoadImage(self):
            self.img_single = self._chk_image_file_(".\\icon\\mon_s.gif")
    
            self.img_single = ImageTk.PhotoImage(self.img_single)
    
            return
    
        def _PatternDialog(self, parent):
    
            self.dlg_width = 1260
            self.dlg_height = 680
            self.dlg_h_btn = 30
            self.dlg_pad = 8
    
            self.dev_dialog = tk.Toplevel(parent,background = 'aliceblue')
    
            title_str = " イメージ表示 : " 
    
            self.dev_dialog.title(title_str)
    
            # MainWindowの表示位置を反映して表示位置を決めたい。
    
            self.dev_dialog.geometry(str(self.dlg_width) + "x"+ str(self.dlg_height) )
    
            _InFrame_ = ttk.Frame(
                self.dev_dialog
                )
    
            _Label_ = tk.Label(
                _InFrame_,
                image = self.img_single
            )
    
    
            _Label_.pack()
            _InFrame_.pack()
    
    
    if __name__ == '__main__':
        screen_obj = class_Pattern_main()
    
        MainWindow_obj = screen_obj.createMainWindow()
    
        MainWindow_obj.after(100,screen_obj._PatternDialog(MainWindow_obj))
        MainWindow_obj.mainloop()
    
    
[/code]


CC BY-SA 4.0
2019-10-08T02:53:58.030
59552
2020-05-10T11:02:00.213
2019-10-11T17:16:01.263
3060
32891
question
python3 tkinter pil
Python PIL ImageTkでRuntimeErrorが発生する。


結論として、呼び出しが早すぎました。 **init** ()において呼び出してしまっているのが原因です。  
子ダイアログを表示させる_PatternDialog関数の先頭にself.LoadImage()を移動させました。  
参考リンクは以下の通りです。

[RuntimeError: Too early to create image - Stack
Overflow](https://stackoverflow.com/questions/53861528/runtimeerror-too-early-
to-create-image)

修正したソースコード

[code]

    #! /usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import tkinter as tk
    from tkinter import ttk
    from PIL import Image,ImageTk,ImageDraw
    
    
    class class_Pattern_main(object):    
        def __init__(self):
    
            self.screen_w = 300
            self.screen_h = 200
            self.dlg_pos_x = 10
            self.dlg_pos_y = 10
            self.dlg_pad = 4
    
            self.sticky = tk.N+tk.S+tk.E+tk.W
    
            # ここではだめなのね
            #self.LoadImage()
    
    
        def createMainWindow(self):
    
            obj = ttk.tkinter.Tk() 
    
            geo_string = str(self.screen_w) + "x" + str(self.screen_h) + "+" + str(self.dlg_pos_x)  + "+" + str(self.dlg_pos_y) 
    
            obj.geometry(geo_string) 
    
            return obj
    
        def _chk_image_file_(self,f_path):
            try:
                # ファイルを読み込んで64x64にリサイズ
                ret_obj = Image.open(f_path).resize((64,64))
            except IOError:
                #Logに残すとか
                msg_text = "{0}{1}{2}".format(self.log_header,"指定されたアイコンファイルが読み込めません。" ,f_path)
    
                # 代わりとなるイメージを作成して返す。
                ret_obj = Image.new('RGB',(64,64),(150,150,150))
                draw = ImageDraw.ImageDraw(ret_obj)
                draw.rectangle((4,4,60,60), fill = None, outline = (250,30,30),width=2)
                draw.line((60,4,4,60), fill = (250,30,30),width=2)
    
            return ret_obj           
    
        def LoadImage(self):
            self.img_single = self._chk_image_file_(".\\icon\\mon_s.gif")
    
            self.img_single = ImageTk.PhotoImage(self.img_single)
    
            return
    
        def _PatternDialog(self, parent):
            self.LoadImage()
    
            self.dlg_width = 1260
            self.dlg_height = 680
            self.dlg_h_btn = 30
            self.dlg_pad = 8
    
            self.dev_dialog = tk.Toplevel(parent,background = 'aliceblue')
    
            title_str = " イメージ表示 : " 
    
            self.dev_dialog.title(title_str)
    
            # MainWindowの表示位置を反映して表示位置を決めたい。
    
            self.dev_dialog.geometry(str(self.dlg_width) + "x"+ str(self.dlg_height) )
    
            _InFrame_ = ttk.Frame(
                self.dev_dialog
                )
    
            _Label_ = tk.Label(
                _InFrame_,
                image = self.img_single
            )
    
    
            _Label_.pack()
            _InFrame_.pack()
    
    
    if __name__ == '__main__':
        screen_obj = class_Pattern_main()
    
        MainWindow_obj = screen_obj.createMainWindow()
    
        MainWindow_obj.after(100,screen_obj._PatternDialog(MainWindow_obj))
        MainWindow_obj.mainloop()
    
[/code]


CC BY-SA 4.0
2019-10-08T02:53:58.030
59553
2019-10-11T17:17:09.800
2019-10-11T17:17:09.800
3060
32891
59552
answer