Next / Previous / Contents / Shipman's homepage

7.4. Controls._setFont(): Font change handler

This method is a generic handler that is called when any font option changes. It tries to build a new font with all the currently selected options. It can fail—for example, if the text in the size field is not a valid integer. Assuming it succeeds, it builds a new font with all the current options, stores it in self._currentFont, and calls the observer function.

This method may be called when the user clicks the button to set the size; in that case it is called with no arguments. By adding a second argument with a default value of None, we can use the same handler for the event bindings on self.sizeField; event handlers get an Event object as an argument.

fontselect.py
    def _setFont(self, event=None):
        """Handler for size button or size field events.

          [ event is an Event object or None ->
              if self's controls describe a valid font ->
                self  :=  self displaying that new font
                call self's observers with that new font
              else ->
                pop up an error dialog ]
        """

The contents of the self.sizeField Entry widget should be a number (in string form). If the text in the field isn't a valid integer, we'll use a pop-up dialog to alert the user. In the Dialog constructor, the default=0 option tells it to use the first button by default, and the strings tuple specifies that there be only one button, labeled "OK".

fontselect.py
        #-- 1 --
        # [ if the text in self.sizeField is an integer ->
        #     sizeValue  :=  that text as an integer
        #   else ->
        #     pop up a dialog
        #     return ]
        try:
            sizeValue = int(self._sizeText.get())
        except ValueError:
            d = Dialog.Dialog(self,
                      title="Message", bitmap="info",
                      text="Size must be an integer.",
                      default=0, strings=("OK",))
            return

It's also an error if no family has ever been selected.

fontselect.py
        #-- 2 --
        # [ if self._currentFamily is None ->
        #     pop up a dialog
        #     return
        #   else -> I ]
        if self._currentFamily is None:
            d = Dialog.Dialog(self,
                      title="Message", bitmap="info",
                      text="No family selected.",
                      default=0, strings=("OK",))
            return

Next we convert the states of the boldface and italic buttons into appropriate values of the weight and slant options for font creation.

fontselect.py
        #-- 3 --
        if self._isBold.get():   weightValue = tkFont.BOLD
        else:                    weightValue = tkFont.NORMAL

This next bit brought out a bug in Tkinter itself. The Tk package wants the slant attribute to be either "italic" (which is available as the constant tkFont.ITALIC) or "roman". However, there is no such constant as tkFont.ROMAN.

fontselect.py
        #-- 4 --
        if self._isItalic.get():  slantValue = tkFont.ITALIC
        else:                     slantValue = "roman"

We have everything we need now: family name, size, and bold and italic attributes. Build the font, apply it to the .sample, and call the observer function if any.

fontselect.py
        #-- 5 --
        # [ self._currentFont  :=  a new font with
        #       family=self._currentFamily, weight=weightValue,
        #       slant=slantValue, and size=sizeValue ]
        self._currentFont = tkFont.Font(family=self._currentFamily,
            size=sizeValue, weight=weightValue, slant=slantValue)

It's a simple matter to change the font of self.sample: we just use its .configure() method. Also get a string describing all the current font options and place it into the annunciator label.

fontselect.py
        #-- 6 --
        # [ self.sample  :=  self.sample with font self._currentFont
        #   self.annunciator  :=  self.annunciator with the actual
        #       name of self._currentFont ]
        self.sample.configure(font=self._currentFont)
        self._fontName.set(self.getName())

        #-- 7 --
        if self._observer:
            self._observer(self._currentFont)