Next / Previous / Contents / Shipman's homepage

5.3. class FontSelect

There are a lot of widgets inside a FontSelect widget. To simplify the spatial and logical organization, we won't deal with all the widgets at the top level. Instead, we'll use a “frames within frames within frames” technique so that the layout and control linkages at each level are relatively simple.

Hence, at this level, our grid plan has only two cells: the family listbox (and associated label) in row 0, column 0, and everything else in row 0, column 1.

To make this division of function crystal-clear, we'll move the logic for each of those two groups into separate classes:

So the work of this class is very simple. It creates and grids the two sub-widgets. It provides the function that the FamilyPicker needs when the family is changed, and when that function is called, it just passes the newly chosen family down to the Controls sub-widget.

In order to make class FontSelect act like any other widget, we declare the class to inherit from Tkinter's Frame widget.

fontselect.py
class FontSelect(tk.Frame):
    """A compound widget for selecting fonts.

Here are the Cleanroom intended functions for the constructor and methods, and declarations of exported attributes. The calling sequence for the observer function is discussed in Section 3, “Using the FontSelect widget in your Tkinter application”.

fontselect.py
      Exports:
        FontSelect(master, font=None, listCount=None, observer=None):
          [ (master is a Frame or None) and
            (font is a tkFont.Font or None) and
            (listCount is an integer, defaulting to LISTBOX_HEIGHT) and
            (observer is a function to be called when the font
            changes) ->
              master  :=  master with a new FontSelect widget added
                          but not gridded, with that font, list count,
                          and observer function
              return that widget ]
        .scrollList:    [ a ScrolledList containing the family names ]
        .get():
          [ if a font has been selected ->
              return that font as a tkFont.Font object
            else -> return None ]
        .getName():
          [ if a font has been selected ->
              return a string describing the actual font
            else -> return None ]
        .addObserver(f):
          [ self  :=  self with a new observer function added ]

So that our subwidgets have access to the fonts created at this level, we make these fonts public attributes.

fontselect.py
        .regularFont:  [ a tkFont.Font for general purposes ]
        .listFont:
           [ if a font option was passed to the constructor ->
               that option's value
             else -> self.regularFont ]

Attributes inside the class include the sub-widgets .familyPicker and .controls, and also three fonts we'll need.

fontselect.py
      Internal widgets:
        .familyPicker:
          [ a FamilyPicker for picking the font family ]
        .controls:
          [ a Controls widget containing other controls ]

      State/Invariants:
        ._listCount:
           [ if a listCount option was passed to the constructor ->
               that option's value
             else -> LISTBOX_HEIGHT ]
        ._observerList:
          [ a list containing all observer callback functions
            for self ]
    """