Next / Previous / Contents / TCC Help System / NM Tech homepage

5. fontselect.py: The module

Here we begin the literate exposition of the actual code. First is a prologue directing the reader back to this documentation.

fontselect.py
"""fontselect.py: FontSelect, a font selector widget for Tkinter.

  For documentation, see:
    http://www.nmt.edu/tcc/help/lang/python/examples/fontselect/
"""

Next, the imported modules: the Tkinter widget set, and its related tkFont module containing the font-related functions. The Dialog module is another Tkinter accessory module that makes it easy to construct a pop-up dialog window.

fontselect.py
#================================================================
# Imports
#----------------------------------------------------------------

from Tkinter import *
import tkFont
import Dialog

We also use a ScrolledList widget, described elsewhere, to hold the list of families and its associated scrollbar. See the separate document, ScrolledList: A Tkinter scrollable list widget.

fontselect.py
import scrolledlist

The manifest constants LISTBOX_HEIGHT and LISTBOX_WIDTH are the default number of lines and line widths in the font family listbox. SAMPLE_TEXT is the initial sample text, and DEFAULT_SIZE is the starting text size.

fontselect.py
#================================================================
# Manifest constants
#----------------------------------------------------------------

LISTBOX_HEIGHT  =  15
LISTBOX_WIDTH   =  30
SAMPLE_TEXT     =  "0O 1lI| ABC abc"
DEFAULT_SIZE    =  14
DEFAULT_FAMILY  =  "helvetica"

5.1. 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:

  • class FamilyPicker contains the family listbox and associated label. It will have a callback linkage, a function that will be called each time the user clicks on a family name.

  • class Controls contains everything else. It will have a method called .setFont() that changes the current family.

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(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 ]
    """