美文网首页python自学
python tkinter图标不显示的原因及完美解决方案

python tkinter图标不显示的原因及完美解决方案

作者: BL_Fang | 来源:发表于2019-06-27 19:25 被阅读77次

    tkinter的按钮、标签等都可以用图标显示,但是可能存在不显示的问题。当然包括多种原因,比如路径不对、图片格式不对等。这些都不是本文要解决的。本文所说的不显示具体指,

    1.在一个函数内生成图标

    def createImageProcess():
        scan1 = icon("skip_forward_16x16.gif").get()
        btn1 = tk.Button(master,image = scan1, text="new")
    

    (请暂且忽略icon,这是我自己定义的一个图片导入类。)
    2.在一个类的方法内生成图标

    class A:
      def createImageProcess(self):
        scan1 = icon("skip_forward_16x16.gif").get()
        btn1 = tk.Button(master,image = scan1, text="new")
    

    3.这一种最为诡异。大概的情况是我已经生成了有图标的按钮,然后再在界面上修改时,原有的图标——嗖——不见了。就像下面这样


    1
    2

    在图1中图标还在,等生成第二个tab的时候,图标不见了(请忽略图2中的蓝色,那是我解决问题以后出现的)

    对于前两种情况产生的原因已经有一些博文解释了,也给出了解决方案。原因是python的垃圾回收机制。当函数运行结束后,其中的局部变量被回收了,图片被销毁。所以,解决方案就是阻止图片被销毁。对于第一种,将图片提到函数外面

     scan1 = icon("skip_forward_16x16.gif").get()
    def createImageProcess():
        btn1 = tk.Button(master,image = scan1, text="new")
    

    第二种,将图片写成类属性

    class A:
      def createImageProcess(self):
        self.scan1 = icon("skip_forward_16x16.gif").get()
        btn1 = tk.Button(master,image = self.scan1, text="new")
    

    但是对于第三种,怕是比较诡异了。我是头一次见到,大概你也是吧。我猜想也还是被回收了。
    如果是小一点的程序,用上边的方法应该够了。但是对于一个复杂的程序,上边的方法始终感觉有些不完美。所以,完美解决这个问题也就成了本文的主旨。
    要想阻止被回收,一种方法是定义全局变量。当然这绝对不是完美的方案。还有一种就是用一个单例。单例是替换全局变量的一个套路解法。但是这里还有一些变化。因为我们的图片有很多个。所以需要修改一下。先上代码

    import os
    import tkinter as tk
    
    class icon(object):
        _instance = {}
        def __init__(self, name):
            self.path = os.path.join(
                    os.path.dirname(os.path.abspath(__file__)), "icons",
                    name)
        
        @classmethod  
        def instance(cls, name):
            if name not in icon._instance.keys():
                i = icon(name)
                icon._instance[name] = i.get() 
            return icon._instance[name]
            
        def get(self):
            return tk.PhotoImage(file = self.path)
    

    这是一个基础版本的单例写法。不同之处在于instance方法中传入了图片名称。用一个公有变量_instance保存了所有已导入的图片。当已经导入时,直接返回。没有导入时,才用tk.PhotoImage导入。
    这个方案用起来很方便。所有的图片保存在icons文件夹下。导入的时候只需要

    tk.Button(master,
              image = icon.instance("file_(add)_16x16.gif"), 
              text="new")
    

    随便在哪个函数、哪个类的方法里用,都不存在问题了。
    要说这个方案也存在一点瑕疵。在多线程的时候图片可能重复导入。要修改得加线程锁。但是,我们只是读取图片。重复导入一张图片也没什么大碍。简简单单的挺美。
    Beautiful!用你肉嘟嘟的小手给我点个赞吧。

    相关文章

      网友评论

        本文标题:python tkinter图标不显示的原因及完美解决方案

        本文链接:https://www.haomeiwen.com/subject/qghdcctx.html