Next / Previous / Contents / Shipman's homepage

7. class Controls: Controls frame

This compound widget contains all the controls for changing the font except for the family-picking apparatus. It has a method that tells it what font family to use. It calls its observer callback whenever any font option is changed.

fontselect.py
class Controls(tk.Frame):
    """Frame for all the small widgets in the application.

      Exports:
        Controls(fontSelect, observer):
          [ (fontSelect is a FontSelect widget) and
            (observer is a callback function or None) ->
              fontSelect  :=  fontSelect with a new Controls widget
                  added but not gridded, with that observer callback
                  if given
              return that new Controls widget ]
        .setFamily(familyName):
          [ familyName is the name of a font family in tkFont ->
              self  :=  self with that font family set ]
        .getName():
          [ return a string describing self's current font ]
        .getFont():
          [ returns self's current font as a tkFont.Font ]

Here is the grid plan and list of internal widgets.

fontselect.py
      Internal widgets:

          0
        +--------------+
      0 | .annunciator | Label:  Shows the current font name.
        +--------------+
      1 | .sample      | Text:  Some sample text in the current font.
        +--------------+
      2 | .buttons     | Frame:  Remaining small controls.
        +--------------+

All the rest of the controls live in the self.buttons Frame.

This class manages both its own grid and the grid inside the .buttons frame. We could have made yet another compound widget class for this frame, but the separation of controls was made for reasons of layout and not because they are really a separate group of controls.

fontselect.py
      Internal widgets inside self.buttons are stacked
       sideways.

       Column
       ------
         0    .sizeLabel: Label, 'Size:'
         1    .sizeField: Entry, text size in pixels
         2    .sizeButton: Button, applies .sizeField
         3        (spacer column, absorbs remaining space)
         4    .boldButton: Checkbutton, turns boldface on and off
         5    .italicButton:  Checkbutton, turns italics on and off

      Control variables:
        ._fontName:
          [ string control variable for .annunciator ]
        ._sizeText:
          [ string control variable for .sizeField ]
        ._isBold:
          [ int control variable for .boldButton ]
        ._isItalic:
          [ int control variable for .italicButton ]

Here are the internal attributes of the class.

fontselect.py
      State/Invariants:
        .fontSelect:   [ self's parent, a FontSelect ]
        ._currentFamily:
          [ if a family has been selected ->
              that family's name as a string
            else -> None ]
        ._currentFont:
          [ if a font has been selected ->
              a tkFont.Font representing that font
            else ->
              None ]
        ._observer:   [ as passed to the constructor, read-only ]
    """

7.1. Controls.__init__(): Constructor

As we create the controls, we'll need access to a number of fonts: fonts for control labels, but also the special italic and bold fonts for the italic and bold buttons. If we stipulate that our parent widget is a FontSelect widget, then we can access these fonts, which are public attributes of that widget.

The constructor starts by calling the parent's constructor. Then we set up the initial invariants for the internal state items, and create the widgets.

fontselect.py
    def __init__(self, fontSelect, observer=None):
        """Constructor for the Controls widget.
        """

        #-- 1 --
        # [ fontSelect  :=  fontSelect with a new Frame added
        #   self  :=  that Frame ]
        tk.Frame.__init__(self, fontSelect)

        #-- 2 --
        self.fontSelect      = fontSelect
        self._currentFont   = None
        self._currentFamily = None

        #-- 3 --
        # [ self  :=  self with all widgets added and gridded ]
        self._createWidgets()

It is necessary to select some family initially. However, the usually family selection logic will call the observer function, and we don't want to do that for the initial selection. So self._observer is set temporarily to None while we select the initial family, and then set correctly afterward.

fontselect.py
        #-- 4 --
        # [ self  :=  self with DEFAULT_FAMILY as the selected family ]
        self._observer = None
        self.setFamily(DEFAULT_FAMILY)

        #-- 5 --
        self._observer = observer