简体   繁体   中英

Cannot get LabelFrame widget to display on ttk notebook (python 3.5.1)

I have an application in which the (tkinter) LabelFrame widget on the tab of a ttk Notebook will not update itself. In a much simplified version of that program (code extracts below) the widget will not even appear on the GUI.

Everything else on the GUI works properly, including updating the tab titles, the application title (and icon) and updating the Label, Checkbutton and Radiobutton widgets on all notebook tabs. Using the ttk versions (eg ttk.LabelFrame) to create those widgets did not fix the issue. I also tried using “update_idletasks” (some think this as a kludge) immediately after updating the widget attributes without success.

In the real application the text of all GUI widgets change according to the state of a “choose language” widget on the same GUI (for details, see: Need Python/tkinter GUI to dynamically update itself (for a multi-lingual GUI) ). It's known that all GUI text values (the WidgetName["text”] attribute), including the missing LabelFrame, are being correctly updated to match the state of that widget.

Is there something “special” about LabelFrame widgets on Notebook tabs? What (probably simple) thing am I overlooking?
Also, any confirmation/denial by others will help determine if the problem is unique to my system - a distinct possiblity since my machine is administered by corporate IM (who don't have the best record when handling the needs of unusual users like me).

Thanks


The following is a complete example of the problem. When run, the LabelFrame widget (which should appear at (0, 0) of Tab 1) does not appear. Clicking on the "language" widget causes everything else to display text in the language selected by the "language" widget.

From “LanguageInUse.py” the code that switches languages:

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  ================================''' 

From “SelectReports.py”) the code that builds the notebook:

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

From “ChangeLanguageOnGui.py” the code that updates all notebook widgets:

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 )    

From "TkinterRoot.py" the code that makes root importable everywhere (explictly importing this avoided problems such as IntVar() being unavailable during the intitialization phase of other modules):

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

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

And finally "A.py", the mainline file:

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()

The Environment is 64-bit Python 3.5.1, 64-bit Win 7 Enterprise SP 1, 64-bit Eclipse Mars 2 (the Java EE IDE edition) running 64-bit PyDev 5.1.2.201606231256. The "one user" (no admin rights) version of Pydev was used, this required Microsoft patch KB2999226 (part of Win10) to run on Win7. Eventual target distribution is a 32-bit Windows app (so it can run on 32 & 64 bit Windows) - and if/when time permits - Linux.

There's one minor complication to keep in mind: In the real program several packages are being used. Inside each package each function is isolated inside its own file. All objects (eg the tkinter widgets) that must be externally visible (or need be shared amongst the package's files) are declared in the package's _ _ init.py _ _ file. Functions that must be externally visible are explicitly imported into _ _ init.py _ _ by using relative imports (eg “from .Function1 import Function1” ).

Your title is misleading because you place the LabelFrame in a Frame, not directly on a Notebook tab. Your problem is that the labelframe does not appear in its parent frame. The Notebook is irrelevant and all associated code should have been deleted before posting.

Even the frame is irrelevant in that the same problem arises when putting the labelframe directly in root. Here is minimal code that demonstrate both the problem and a solution.

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()

I ran this on Win 10 with 3.6a2, which comes with tk 8.6.4. Only lf2 is visible because the default size of a labelframe, as with a frame, is 0 x 0. A non-default size arises either from explicit sizing or from contents. Somewhat surprisingly, the label does not count as content and does not force a non-default size. I reproduced the same result with the labelframe in a frame (your situation) and on a tab.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM