【问题标题】:Cannot get LabelFrame widget to display on ttk notebook (python 3.5.1)无法让 LabelFrame 小部件显示在 ttk 笔记本上(python 3.5.1)
【发布时间】:2023-03-23 15:54:01
【问题描述】:

我有一个应用程序,其中 ttk Notebook 选项卡上的 (tkinter) LabelFrame 小部件不会自行更新。在该程序的一个非常简化的版本中(代码摘录如下),小部件甚至不会出现在 GUI 上。

GUI 上的其他一切都正常工作,包括更新选项卡标题、应用程序标题(和图标)以及更新所有笔记本选项卡上的标签、检查按钮和单选按钮小部件。使用 ttk 版本(例如 ttk.LabelFrame)来创建这些小部件并不能解决问题。我还尝试在更新小部件属性后立即使用“update_idletasks”(有些人认为这是一个杂物)但没有成功。

在实际应用程序中,所有 GUI 小部件的文本都会根据同一 GUI 上“选择语言”小部件的状态而变化(有关详细信息,请参阅:Need Python/tkinter GUI to dynamically update itself (for a multi-lingual GUI))。众所周知,所有 GUI 文本值(WidgetName["text"] 属性),包括缺少的 LabelFrame,都正在正确更新以匹配该小部件的状态。

Notebook 选项卡上的 LabelFrame 小部件有什么“特别”之处吗?我忽略了什么(可能很简单)?
此外,其他人的任何确认/拒绝都将有助于确定问题是否是我的系统所独有的——这是一种独特的可能性,因为我的机器是由公司 IM 管理的(在处理像我这样的不寻常用户的需求时,他们没有最好的记录) .

谢谢


以下是该问题的完整示例。运行时,LabelFrame 小部件(应出现在选项卡 1 的 (0, 0) 处)不会出现。单击“语言”小部件会使其他所有内容以“语言”小部件选择的语言显示文本。

从“LanguageInUse.py”中切换语言的代码:

import sys

c_cedille_lower    = "\u00E7" #  UTF 8/16 (code page 863?) French character
e_circumflex_lower = "\u00EA"

English  = 'English'                            # string shown on GUI
Francais = 'Fran' + c_cedille_lower + 'ais'    # string shown on GUI

DefaultLanguage = Francais
DefaultLanguage = English       # comment out this line to use French

user_language = DefaultLanguage     # set up language shown on GUI

# Define all language-dependent GUI strings (as "Application-Level" globals)

ComplianceMessage   = None
ReportTab1Title     = None
ReportTab2Title     = None
XCheckbuttonMessage = None
XLabelFrameMessage  = None
XLabelMessage       = None
XRadioButtonMessage = None

'''=========================================================================='''

def SetGuiLanguage( user_language ) :

    global  ComplianceMessage, LanguagePrompt        
    global  ReportTab1Title, ReportTab2Title 
    global XLabelFrameMessage, XCheckbuttonMessage, XLabelMessage, XRadioButtonMessage

    if ( user_language == English ):    
        LanguagePrompt      = "Language"
        ReportTab1Title     = "Message Counts"
        ReportTab2Title     = "Communications Compliance"
        XLabelFrameMessage  = "LabelFrame"
        XCheckbuttonMessage = "Checkbox"
        XLabelMessage       = "Label"
        XRadioButtonMessage = 'Radiobutton'
        ComplianceMessage  = "Compliance (engish)"        
    elif ( user_language == Francais ):    
        LanguagePrompt     = "Langage"
        ReportTab1Title    = "Comtes de message"
        ReportTab2Title    = "Compliance Communications"
        XLabelFrameMessage  = "LabelFrame en "  + Francais
        XCheckbuttonMessage = "Checkbox en "    + Francais
        XLabelMessage       = "Label en "       + Francais
        XRadioButtonMessage = "Radiobutton en " + Francais
        ComplianceMessage  =  "Compliance - "   + Francais        
    else:   
        print (' An unknown user language was specified' )   
        sys.exit()

    return

'''==========================================================================''' 

SetGuiLanguage( user_language )     # initialize all tkinter strings at startup

'''==========================  End of File  ================================''' 

来自“SelectReports.py”)构建笔记本的代码:

from tkinter import Checkbutton, Radiobutton, Label, LabelFrame, Frame
from tkinter import ttk 

import LanguageInUse

# Locally defined entities importable by other modules (often
# Tkinter Application level objects whose language can be changed)

ComplianceMessageText    = None
NotebookFrame            = None

XCheckbutton = None
XLabel       = None
XLabelFrame  = None  # NOT APPEARING ON THE GUI 
XRadiobutton = None

'''==========================================================================''' 

def TabbedReports( ParentFrame ) :

    global ComplianceMessageText,  NotebookFrame 
    global SelectReportFrame, UplinkFileWarningText 
    global XCheckbutton, XLabel, XLabelFrame, XRadiobutton

    # Builds the notebook and it's widgits

    NotebookFrame = ttk.Notebook( ParentFrame )   
    NotebookFrame.grid( row = 0, column = 1 )

    Tab1Frame = Frame( NotebookFrame ) 
    Tab2Frame = Frame( NotebookFrame ) 

    NotebookFrame.add( Tab1Frame )
    NotebookFrame.add( Tab2Frame )

    # Create widgets on Tab 1

    XLabelFrame  = LabelFrame(  Tab1Frame )  # NOT APPEARING ON GUI
    XCheckbutton = Checkbutton( Tab1Frame )
    XLabel       = Label(       Tab1Frame )
    XRadiobutton = Radiobutton( Tab1Frame )

    XLabelFrame.grid(  row = 1, column = 0 )  # NOT ON GUI 
    XCheckbutton.grid( row = 1, column = 1 )    
    XLabel.grid(       row = 2, column = 0 )  
    XRadiobutton.grid( row = 2, column = 1 )

    XLabelFrame.configure(  text = LanguageInUse.XLabelFrameMessage )   # NOT ON GUI 
    XCheckbutton.configure( text = LanguageInUse.XCheckbuttonMessage )
    XLabel.configure(       text = LanguageInUse.XLabelMessage )
    XRadiobutton.configure( text = LanguageInUse.XRadioButtonMessage )

     #  .tab() gives same effect as .configure() for other widget types 

    NotebookFrame.tab( 0 , text = LanguageInUse.ReportTab1Title )
    NotebookFrame.tab( 1 , text = LanguageInUse.ReportTab2Title )

    # Create the only widget on Tab 2  (uses other method to specify text)

    ComplianceMessageText = Label( Tab2Frame )
    ComplianceMessageText.grid(  row = 0, column = 0 )    
    ComplianceMessageText['text']  = LanguageInUse.ComplianceMessage 

    return

从“ChangeLanguageOnGui.py”更新所有笔记本小部件的代码:

import sys, os
from tkinter import StringVar, Radiobutton, PhotoImage

#from TkinterRoot import root

import LanguageInUse
import SelectReports

'''==========================================================================''' 

def ChangeLanguageOnGui() :    

    SelectReports.XLabelFrame.configure(  text = LanguageInUse.XLabelFrameMessage )   # NOT ON GUI 
    SelectReports.XCheckbutton.configure( text = LanguageInUse.XCheckbuttonMessage )
    SelectReports.XLabel.configure(       text = LanguageInUse.XLabelMessage )
    SelectReports.XRadiobutton.configure( text = LanguageInUse.XRadioButtonMessage )

    #  .tab() gives the same effect as .configure() for other widget types

    SelectReports.NotebookFrame.tab( 0 , text = LanguageInUse.ReportTab1Title )
    SelectReports.NotebookFrame.tab( 1 , text = LanguageInUse.ReportTab2Title )

    SelectReports.ComplianceMessageText['text']  = LanguageInUse.ComplianceMessage

'''==========================================================================''' 

def SetUpGuiLanguage( LanguageFrame ) :

    GUI_Language = StringVar( value = LanguageInUse.user_language )

    #---------------------------------------------------------------------------
    def switchLanguage():  

        LanguageInUse.user_language = GUI_Language.get()                
        LanguageInUse.SetGuiLanguage( LanguageInUse.user_language )   

        ChangeLanguageOnGui()

        return

    #---------------------------------------------------------------------------

    UsingEnglish = Radiobutton( LanguageFrame, indicatoron = False,
                                variable = GUI_Language,
                                command = lambda: switchLanguage(),
                                value =  LanguageInUse.English )  
    UsingFrancais = Radiobutton( LanguageFrame, indicatoron = False,
                                 variable = GUI_Language,
                                 command = lambda: switchLanguage(),
                                 value = LanguageInUse.Francais )    
    UsingEnglish.grid(  row = 0, column = 0 )    
    UsingFrancais.grid( row = 1, column = 0 )

    UsingEnglish.configure(  text = LanguageInUse.English )
    UsingFrancais.configure( text = LanguageInUse.Francais )    

从“TkinterRoot.py”中,使根在任何地方都可导入的代码(显式导入避免了 IntVar() 在其他模块的初始化阶段不可用等问题):

from tkinter import Tk  # possibly the worlds shortest useful python module

root = Tk()             # makes root an importable "Application Level" global

最后是“A.py”,主线文件:

from TkinterRoot import root 

from tkinter import LabelFrame
from tkinter import ttk

import ChangeLanguageOnGui, LanguageInUse, SelectReports, sys

LanguageFrame      = None

if __name__ == "__main__":

    LanguageChoice = LanguageInUse.English 

    if ( LanguageChoice == LanguageInUse.English ) :
        LanguageInUse.user_language = LanguageChoice
    elif ( LanguageChoice == 'Francais' ) :
        LanguageInUse.user_language = LanguageInUse.Francais
    else :
        print( "Unknown Language: " + LanguageChoice  )
        sys.exit()

    mainframe = ttk.Frame( root )
    mainframe.grid( row = 0, column = 0 )

    LanguageFrame = LabelFrame( mainframe, text = LanguageInUse.LanguagePrompt )
    LanguageFrame.grid( row = 0, column = 0 )

    ChangeLanguageOnGui.SetUpGuiLanguage( LanguageFrame )

    SelectReports.TabbedReports( mainframe ) 

    try:  
        root.mainloop()     
    except:
        print( 'Exception Occurred' )        

sys.exit()

环境是 64 位 Python 3.5.1、64 位 Win 7 Enterprise SP 1、64 位 Eclipse Mars 2(Java EE IDE 版本),运行 64 位 PyDev 5.1.2.201606231256。使用了 Pydev 的“单用户”(无管理员权限)版本,这需要 Microsoft 补丁 KB2999226(Win10 的一部分)才能在 Win7 上运行。最终的目标分发是一个 32 位 Windows 应用程序(因此它可以在 32 位和 64 位 Windows 上运行) - 如果/当时间允许 - Linux。

要记住一个小问题:在实际程序中使用了多个包。在每个包中,每个函数都被隔离在自己的文件中。所有必须在外部可见(或需要在包的文件之间共享)的对象(例如 tkinter 小部件)都在包的 _ _ init.py _ _ 文件中声明。必须在外部可见的函数通过使用相对导入显式导入到 _ _ init.py _ _ 中(例如“from .Function1 import Function1”)。

【问题讨论】:

  • 请阅读stackoverflow.com/help/mcve并采取行动。
  • 问题已更新,包含重现问题所需的所有(最少)代码。
  • 重新阅读链接。一个最小的答案没有不需要证明问题的行。我花了 5 行。

标签: python python-3.x user-interface tkinter ttk


【解决方案1】:

您的标题具有误导性,因为您将 LabelFrame 放在 Frame 中,而不是直接放在 Notebook 选项卡上。您的问题是 labelframe 没有出现在其父框架中。 Notebook 无关紧要,所有相关代码都应该在发布前删除。

即使是框架也无关紧要,因为将标签框架直接放在根目录时也会出现同样的问题。这是演示问题和解决方案的最少代码。

from tkinter import Tk
from tkinter import ttk

root = Tk()
lf1 = ttk.LabelFrame(root, text='labelframe 1')
lf2 = ttk.LabelFrame(root, text='labelframe 2', width=200, height=100)
lf1.pack()
lf2.pack()

我在 tk 8.6.4 附带的 3.6a2 的 Win 10 上运行它。只有 lf2 是可见的,因为标签框的默认大小与框架一样,是 0 x 0。非默认大小来自显式大小或内容。有点令人惊讶的是,标签不算作内容,也不会强制使用非默认大小。我在框架(您的情况)和选项卡上使用 labelframe 复制了相同的结果。

【讨论】:

  • 标题是正确的,但我知道是什么导致了混乱。将笔记本放在选项卡 1 上的框架中是我忘记从代码中删除的原始代码中的工件。上面发布的修订(完整和最小)示例代码(它包括“交换语言”小部件)省略了该框架。其他人确认/否认问题会有所帮助,因为由于问题中的原因,问题可能是我的系统所独有的。
  • 确认什么?正如我确认和解释的那样,XLabelFrame = LabelFrame( Tab1Frame ) 是不可见的(`# NOT APPEARING ON GUI`),因为它的大小是 0 x 0,无论你把它放在哪里。
  • 谢谢,完全忘记了默认为零的大小。将宽度和高度选项添加到 LabelFrame 修复了它。奇怪的是,在单语言版本中,LabelFrame 小部件不需要这些参数,可能是因为该小部件不是动态的并且默认为 text 参数的宽度)。顺便说一句,我预感到我用一个等效的模块替换了有问题的包。这解决了问题,意味着我的包结构有问题,)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-21
  • 2018-10-13
  • 1970-01-01
相关资源
最近更新 更多