无法让 LabelFrame 小部件显示在 ttk 笔记本上 (python 3.5.1)
Cannot get LabelFrame widget to display on ttk notebook (python 3.5.1)
我有一个应用程序,其中 ttk Notebook 选项卡上的 (tkinter) LabelFrame 小部件不会自行更新。在该程序的简化版本(下面的代码摘录)中,小部件甚至不会出现在 GUI 上。
GUI 上的其他一切工作正常,包括更新选项卡标题、应用程序标题(和图标)以及更新所有笔记本选项卡上的 Label、Checkbutton 和 Radiobutton 小部件。使用 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 小部件有什么“特别”之处吗?我忽略了什么(可能很简单)的东西?
此外,其他人的任何 confirmation/denial 都将有助于确定问题是否是我的系统独有的——这是一个明显的可能性,因为我的机器是由公司 IM 管理的(在处理异常用户的需求时,他们没有最好的记录,比如我)。
谢谢
下面是问题的完整示例。当 运行 时,LabelFrame 小部件(应该出现在选项卡 1 的 (0, 0) 处)不会出现。单击 "language" 小部件会导致其他所有内容以 "language" 小部件选择的语言显示文本。
来自“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" 使 root 随处可导入的代码(显式导入此代码避免了 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位Python3.5.1、64位Win 7 Enterprise SP 1、64位Eclipse Mars 2(JavaEEIDE版) 运行宁 64 位 PyDev 5.1.2.201606231256。使用了 Pydev 的 "one user"(无管理员权限)版本,这需要 Microsoft 补丁 KB2999226(Win10 的一部分)到 Win7 上的 运行。最终的目标分发是 32 位 Windows 应用程序(因此它可以 运行 在 32 位和 64 位 Windows 上)- 并且 if/when 时间允许 - Linux。
需要记住一个小问题:在实际程序中使用了多个包。在每个包中,每个函数都被隔离在它自己的文件中。所有必须在外部可见(或需要在包的文件之间共享)的 objects(例如 tkinter 小部件)都在包的 _ _ init.py _ _ 文件中声明。必须对外部可见的函数通过使用相对导入(例如“from .Function1 import Function1”)显式导入_ _ init.py _ _。
您的标题具有误导性,因为您将 LabelFrame 放在框架中,而不是直接放在笔记本选项卡上。您的问题是 labelframe 没有出现在其 parent 框架中。 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()
我 运行 这是在带有 3.6a2 的 Win 10 上,它与 tk 8.6.4 一起提供。只有 lf2 可见,因为标签框的默认大小与框架一样是 0 x 0。non-default 大小来自显式大小调整或内容。有点令人惊讶的是,该标签不算作内容,也不会强制使用 non-default 大小。我在框架(您的情况)和选项卡上使用标签框重现了相同的结果。
我有一个应用程序,其中 ttk Notebook 选项卡上的 (tkinter) LabelFrame 小部件不会自行更新。在该程序的简化版本(下面的代码摘录)中,小部件甚至不会出现在 GUI 上。
GUI 上的其他一切工作正常,包括更新选项卡标题、应用程序标题(和图标)以及更新所有笔记本选项卡上的 Label、Checkbutton 和 Radiobutton 小部件。使用 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 小部件有什么“特别”之处吗?我忽略了什么(可能很简单)的东西?
此外,其他人的任何 confirmation/denial 都将有助于确定问题是否是我的系统独有的——这是一个明显的可能性,因为我的机器是由公司 IM 管理的(在处理异常用户的需求时,他们没有最好的记录,比如我)。
谢谢
下面是问题的完整示例。当 运行 时,LabelFrame 小部件(应该出现在选项卡 1 的 (0, 0) 处)不会出现。单击 "language" 小部件会导致其他所有内容以 "language" 小部件选择的语言显示文本。
来自“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" 使 root 随处可导入的代码(显式导入此代码避免了 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位Python3.5.1、64位Win 7 Enterprise SP 1、64位Eclipse Mars 2(JavaEEIDE版) 运行宁 64 位 PyDev 5.1.2.201606231256。使用了 Pydev 的 "one user"(无管理员权限)版本,这需要 Microsoft 补丁 KB2999226(Win10 的一部分)到 Win7 上的 运行。最终的目标分发是 32 位 Windows 应用程序(因此它可以 运行 在 32 位和 64 位 Windows 上)- 并且 if/when 时间允许 - Linux。
需要记住一个小问题:在实际程序中使用了多个包。在每个包中,每个函数都被隔离在它自己的文件中。所有必须在外部可见(或需要在包的文件之间共享)的 objects(例如 tkinter 小部件)都在包的 _ _ init.py _ _ 文件中声明。必须对外部可见的函数通过使用相对导入(例如“from .Function1 import Function1”)显式导入_ _ init.py _ _。
您的标题具有误导性,因为您将 LabelFrame 放在框架中,而不是直接放在笔记本选项卡上。您的问题是 labelframe 没有出现在其 parent 框架中。 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()
我 运行 这是在带有 3.6a2 的 Win 10 上,它与 tk 8.6.4 一起提供。只有 lf2 可见,因为标签框的默认大小与框架一样是 0 x 0。non-default 大小来自显式大小调整或内容。有点令人惊讶的是,该标签不算作内容,也不会强制使用 non-default 大小。我在框架(您的情况)和选项卡上使用标签框重现了相同的结果。