【问题标题】:Unable use tk.mainloop() in tkinter on ubuntu 16.04.2无法在 ubuntu 16.04.2 上的 tkinter 中使用 tk.mainloop()
【发布时间】:2018-09-27 03:07:24
【问题描述】:

每当我尝试在 ubuntu 16.04.2 上使用 tk.mainloop() 运行简单的 tkinter 程序或任何适用于该母校的程序时,我都无法打开应用程序窗口,并且窗口图标上会显示一个问号。

这是我正在运行的程序:

import tkinter as tk

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super(MainApplication, self).__init__(parent, *args, **kwargs)

if __name__ == '__main__':
    root = tk.Tk()
    MainApplication(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

下面是我运行程序时显示程序输出的屏幕截图:

在此之前,我收到一条错误消息,提示 _tkinter 可以加载。为了解决这个问题,我使用sudo apt-get update 然后sudo apt-get install python3-tk 为ubuntu 下载了最新版本的tkinter。如果这也很重要,我在 Windows 10 的双启动配置中使用 ubuntu。

我也读过How can I fix program icons that appear as a question mark in the Launcher?Why do some open applications appear as “question marks” in the Unity launcher?,但这些问题似乎是关于如何修复应用程序桌面图标,而不是如何修复无法运行的应用程序。此外,问题似乎与特定的 ubuntu 应用程序有关。

有谁知道为什么 ubuntu 不能正确运行 tkinter 应用程序以及可以做些什么来解决这个问题?

【问题讨论】:

    标签: python python-3.x ubuntu tkinter ubuntu-16.04


    【解决方案1】:

    虽然看起来不像,但tkinter 窗口实际上就在那里。它很小很容易看到,因为它内部没有小部件来扩展它。一旦您开始向窗口添加小部件,它就会变得可见。

    例如,要使用相关代码显示一个窗口,

    import tkinter as tk
    
    
    class MainApplication(tk.Frame):
        def __init__(self, parent, *args, **kwargs):
            super(MainApplication, self).__init__(parent, *args, **kwargs)
    
    
    if __name__ == '__main__':
        root = tk.Tk()
        MainApplication(root).pack(side="top", fill="both", expand=True)
        root.mainloop() 
    

    您可以添加一个tk.Button() 小部件来强制窗口展开:

    import tkinter as tk
    
    
    class MainApplication(tk.Frame):
        def __init__(self, parent, *args, **kwargs):
            super(MainApplication, self).__init__(parent, *args, **kwargs)
            # create a button widget to force the window to expand to fit
            # the button
            self.btn = tk.Button(self, text='btn', bg='blue')
            self.btn.pack(side='bottom')
    
    
    if __name__ == '__main__':
        root = tk.Tk()
        MainApplication(root).pack(side="top", fill="both", expand=True)
        root.mainloop()
    

    其中显示以下窗口:

    【讨论】:

    • 我想通知您,而不是批评您:您所说的是错误的。快速证明:在终端上运行这个:import tkinter as tk 然后tk.Tk() 你会看到一个清晰可见的顶层框架。另一个证明是我在回答中提供的第二个 MVCE。我在回答中涵盖了您在此处所说的内容。我再重复一遍;好的做法是使用pack(),就像我在我提供的第一个 MVCE 中所做的那样(不这样做是我在回答中解释的你面临的问题的部分原因)
    • @BillalBEGUERADJ:您提出的两条线将显示一个窗口是正确的。 had 的问题有一个关键的区别:它有一个额外的 1 像素帧,导致整个窗口缩小。这个答案是 100% 正确的。
    【解决方案2】:

    尝试像这样改变程序的主要部分:

    if __name__ == '__main__':
        root = tk.Tk()
        your_class_instance = MainApplication(root)
        print(your_class_instance)
        root.mainloop()
    

    您会在终端上看到如下内容:.140449273960656

    现在让我们回到你原来的代码:

     if __name__ == '__main__':
            root = tk.Tk()
            your_class_instance = MainApplication(root).pack(side="top", fill="both", expand=True)
            print(your_class_instance)
            root.mainloop()
    

    您将在终端上看到None

    为什么? 那是因为 tkinter 的布局管理器(pack()place() grid())总是返回NoneMainApplication 类没有小部件。

    换句话说,你试图什么都不显示。

    注意pack(your_options_list)在这行没有用:

    MainApplication(root).pack(side="top", fill="both", expand=True)
    

    它不仅没有用,而且还阻止了应用程序进一步的可扩展性,因为没有办法使用MainApplication 类的实例。

    也许这对于您的实际问题不是必需的,但只是作为一个旁注,由于您使用的是 Python 3,因此您可以使用:super().__init__(parent, *args, **kwargs) 而不是 super(MainApplication, self).__init__(parent, *args, **kwargs)

    证明提供的解释。

    我为您的问题提供的解释(上述为什么?)指出有 2 个事实导致您出现这种情况。如果满足其中一个,问题就消失了:

    1. pack() 留在原处,但要求MainApplication 至少绘制一个小部件:

      import tkinter as tk
      
      
      class MainApplication(tk.Frame):
          def __init__(self, parent, *args, **kwargs):
              super(MainApplication, self).__init__(parent, *args, **kwargs)
              # I add these 2 following lines
              self.parent = parent
              self.initialize_gui()
      
      def initialize_gui(self):
         # Ok, let us draw one useless button for a test
         self.button_1 = tk.Button(self.parent, text="Do nothing")
         self.button_1.pack()
      
      
      if __name__ == '__main__':
          root = tk.Tk()
          MainApplication(root).pack(side="top", fill="both", expand=True)
          root.mainloop()
      

    您将看到 GUI:

    1. MainApplication 类不绘制任何小部件,但删除pack()

      import tkinter as tk
      
      
      class MainApplication(tk.Frame):
          def __init__(self, parent, *args, **kwargs):
              super(MainApplication, self).__init__(parent, *args, **kwargs)       
      
      
      if __name__ == '__main__':
          root = tk.Tk()
          MainApplication(root) # Remove pack(...)
          root.mainloop()
      

    你可以看到图形用户界面:

    【讨论】:

    • MainApplication(root).pack() 不是没用的;它打包帧,将根显示区域缩小到帧的大小,在测试用例中为 0x0。发布的程序从 IDLE 编辑器按预期在 Windows 上运行,显示一个最小的(仅标题栏)Tk() 窗口,否则是正常的(可以移动、最大化或图标化)。您的编辑表明,仅标题栏的窗口在使用中的 Ubuntu 图形管理器上表现不同,并且(相当无用)未显示并且无法正常工作。
    • "请注意 pack(your_options_list) 在这一行没有用[...]" - 真的吗?这很奇怪,因为正如上面的@TerryJanReedy 所说,这个程序在 Windows 上完美运行。另外,我问题中的代码不是我自己的。我在 Bryan Oakley 对this 问题的回答中使用了它。不过我会尝试你的建议。
    • 您的权利。当我从代码中删除 .pack() 时,程序运行良好,显示了一个小的 tkinter 窗口。但是,我不认为 .pack() 部分没用,因为 Oakley 先生在我上述评论的示例中使用了它。
    • @algerbrex:正确。 pack 在这种情况下不是没用。它有一个非常真实的目的。
    • @BryanOakley 我说它没用,因为放置元素的自然方式就像我在提供的第一个 MCVE 中所做的那样。使用pack() OP 提供的方式充其量是代码重复,并且它更糟糕地阻止了可伸缩性(因为我们不能使用我们刚刚创建的类实例,正如我所解释的)
    猜你喜欢
    • 2017-09-03
    • 2017-12-14
    • 2017-08-20
    • 1970-01-01
    • 2017-12-27
    • 2017-07-30
    • 2018-10-14
    • 2022-08-03
    • 2020-06-20
    相关资源
    最近更新 更多