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.
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.
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
This class manages both its own grid and the grid inside
.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.
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.
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 ] """
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.
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.
#-- 4 -- # [ self := self with DEFAULT_FAMILY as the selected family ] self._observer = None self.setFamily(DEFAULT_FAMILY) #-- 5 -- self._observer = observer