Python Tkinter on Debian Beaglebone: lost font styling when changed directory name
Question: I have installed non-system fonts onto BeagleBone Black (Debian Jessie) and
have been using them in a GUI created using python 2.7 script via Tkinter and
tkFont. When I changed the name of the directory my file was stored in, these
fonts stopped appearing in my python script GUI!

I installed the fonts into /usr/shared/fonts and they are still there, of
course, but somehow I lost the connection to the fonts from my script.

I ran `fc-cache -fv` and rebooted. I ran a short script with

    
    
    list( tkFont.families() )
    

in it, any the fonts I want to use appear in the list.

Still displaying system font in the GUI.

How can it be? Here is my code:

    
    
    #!/usr/bin/python
    
    import time
    import threading
    import Queue
    
    import Tkinter as tk
    import tkFont
    
    try:
        import alsaaudio as aa
        import audioop
        import Adafruit_BBIO.GPIO as GPIO
        debug = False
    except ImportError:
        # To enable simple testing on systems without alsa/gpio
        import mock
    
        aa = mock.MagicMock()
        aa.PCM().read.return_value = (1, '')
    
        audioop = mock.MagicMock()
        audioop.max.return_value = 5000
    
        GPIO = mock.MagicMock()
    
        import random
        GPIO.input.side_effect = lambda *a: random.randint(0, 5000) == 0
    
        debug = True
    
    # layout ########################################################
    
    BACKGROUND_COLOR = '#000000'
    
    TEXTBOX_WIDTH = 1920
    
    # vertical alignment of text in percentages from top
    
    V_ALIGN_L1 = .16
    V_ALIGN_L2 = .28
    V_ALIGN_HEADER = .52
    V_ALIGN_SCORE = .68
    V_ALIGN_TILT = .50
    V_ALIGN_AGAIN = .68
    
    # type ##########################################################
    
    TYPEFACE_L1 = 'Avenir Next Demi Bold'
    TYPEFACE_L2 = 'Avenir Next Bold'
    TYPEFACE_HEADER = 'Avenir Next Bold'
    TYPEFACE_SCORE = 'Avenir Next Demi Bold'
    TYPEFACE_TILT = 'Avenir Next Bold'
    TYPEFACE_AGAIN = 'Avenir Next Bold'
    
    WEIGHT_L1 = tkFont.NORMAL
    WEIGHT_L2 = tkFont.BOLD
    WEIGHT_HEADER = tkFont.BOLD
    WEIGHT_SCORE = tkFont.NORMAL
    WEIGHT_TILT = tkFont.BOLD
    WEIGHT_AGAIN = tkFont.BOLD
    
    FONT_SIZE_L1 = 56
    FONT_SIZE_L2 = 56
    FONT_SIZE_HEADER = 76
    FONT_SIZE_SCORE = 168
    FONT_SIZE_TILT = 114
    FONT_SIZE_AGAIN = 76
    
    LINE_HEIGHT_L1 = -5
    LINE_HEIGHT_L2 = -5
    LINE_HEIGHT_HEADER = -10
    LINE_HEIGHT_SCORE = -20
    LINE_HEIGHT_TILT = -20
    LINE_HEIGHT_AGAIN = -1
    
    TEXT_COLOR_HIGHLIGHT = '#FFFFFF'
    TEXT_COLOR_BODY = '#92C73D'
    
    # text ###########################################################
    
    L1 = 'Try to beat your own score.'
    L2 = 'The lowest score wins!'
    HEADER_MESSAGE = 'Your Score:'
    TILT_MESSAGE = 'Too loud!'
    TRY_AGAIN = 'Start again!'
    
    # audio collection configuration ##################################
    
    BUTTON_PIN = 'P8_12'
    
    DEVICE = 'hw:1'  # hardware sound card index
    CHANNELS = 2
    SAMPLE_RATE = 44100  # Hz
    PERIOD = 256  # Frames
    FORMAT = aa.PCM_FORMAT_S16_LE  # Sound format
    
    NOISE_THRESHOLD = 0  # to eliminate small noises, scale of 0 - 7
    TILT_THRESHOLD = 100.0 # upper limit of score before tilt state
    SCALAR = 4680 # normalizes score, found by trial and error
    UPDATE_TIME = 100 # ms
    
    # start script ###################################################
    
    class Display(object):
    
        def __init__(self, parent, queue, stop_event):
            self.parent = parent
            self.queue = queue
            self.stop_event = stop_event
            self.tilt_event = threading.Event()
    
            self._geom = '200x200+0+0'
            parent.geometry("{0}x{1}+0+0".format(
                parent.winfo_screenwidth(), parent.winfo_screenheight()))
            parent.overrideredirect(1)
    
            parent.title(TITLE)
            parent.configure(background=BACKGROUND_COLOR)
            self.create_text()
            self.process_queue()
    
            self.audio_thread = threading.Thread(target=self.setup_audio)
            self.audio_thread.start()
    
        def __delete__(self, instance):
            instance.stop_event.set()
    
        def create_text(self):
            message_kwargs = dict(
                bg=BACKGROUND_COLOR,
                width=TEXTBOX_WIDTH,
                justify='c',
            )
    
            self.message_L1 = tk.Message(
                self.parent,
                text=L1,
                fg=TEXT_COLOR_HIGHLIGHT,
                font=(TYPEFACE_HEADER, FONT_SIZE_L1, WEIGHT_L1),
                pady=LINE_HEIGHT_L1,
                **message_kwargs)
    
            self.message_L2 = tk.Message(
                self.parent,
                text=L2,
                fg=TEXT_COLOR_HIGHLIGHT,
                font=(TYPEFACE_HEADER, FONT_SIZE_L2, WEIGHT_L2),
                pady=LINE_HEIGHT_L2,
                **message_kwargs)
    
            self.message_score_header = tk.Message(
                self.parent,
                text=HEADER_MESSAGE,
                fg=TEXT_COLOR_BODY,
                font=(TYPEFACE_HEADER, FONT_SIZE_HEADER, WEIGHT_HEADER),
                pady=LINE_HEIGHT_HEADER,
                **message_kwargs)
            self.message_score = tk.Message(
                self.parent,
                text='0.0',
                fg=TEXT_COLOR_HIGHLIGHT,
                font=(TYPEFACE_SCORE, FONT_SIZE_SCORE, WEIGHT_SCORE),
                pady=LINE_HEIGHT_SCORE,
                **message_kwargs)
    
            self.message_L1.place(relx=.5, rely=V_ALIGN_L1, anchor='c')
            self.message_L2.place(relx=.5, rely=V_ALIGN_L2, anchor='c')
            self.message_score_header.place(relx=V_ALIGN_HEADER, rely=.5, anchor='c')
            self.message_score.place(relx=.5, rely=V_ALIGN_SCORE, anchor='c')
    
        def process_queue(self):
            text = None
            while not self.queue.empty():
                text = self.queue.get_nowait()
    
            if text:
                self.message_score_header.configure(text=HEADER_MESSAGE)
                self.message_score.configure(text=text)
            elif self.tilt_event.is_set():
                self.message_L1.configure(text="")
                self.message_L2.configure(text="")
                self.message_score_header.configure(text=TILT_MESSAGE, fg=TEXT_COLOR_HIGHLIGHT, font=(TYPEFACE_TILT, FONT_SIZE_TILT, WEIGHT_TILT), pady=LINE_HEIGHT_TILT)
                self.message_score.configure(text=TRY_AGAIN, fg=TEXT_COLOR_BODY, font=(TYPEFACE_AGAIN, FONT_SIZE_AGAIN, WEIGHT_AGAIN), pady=LINE_HEIGHT_AGAIN)
                self.message_score.place(relx=.75, rely=V_ALIGN_AGAIN, anchor='c')
    
            self.parent.after(UPDATE_TIME, self.process_queue)
    
        def setup_audio(self):
            data_in = aa.PCM(aa.PCM_CAPTURE, aa.PCM_NONBLOCK, DEVICE)
            data_in.setchannels(2)
            data_in.setrate(SAMPLE_RATE)
            data_in.setformat(FORMAT)
    
            data_in.setperiodsize(PERIOD)
    
            score = 0
            running = False
    
            while not self.stop_event.is_set():
                # Sleep a very short time to prevent the thread from locking up
                time.sleep(0.001)
    
                if GPIO.input(BUTTON_PIN):
                    self.tilt_event.clear()
                    score = 0
                    if not running:
                        self.message_L1.configure(text=L1)
                        self.message_L2.configure(text=L2)
                        self.message_score_header.configure(text=HEADER_MESSAGE, fg=TEXT_COLOR_BODY, font=(TYPEFACE_HEADER, FONT_SIZE_HEADER, WEIGHT_HEADER), pady=LINE_HEIGHT_HEADER)
                        self.message_score.configure(text='0.0', fg=TEXT_COLOR_HIGHLIGHT, font=(TYPEFACE_SCORE, FONT_SIZE_SCORE, WEIGHT_SCORE), pady=LINE_HEIGHT_SCORE)
                        self.message_score.place(relx=.5, rely=V_ALIGN_SCORE, anchor='c')
    
                        running = True
                    self.queue.put('0.0')
                elif not running:
                    # Not running yet, keep waiting
                    continue
    
                # Read data from device
                l, data = data_in.read()
                if l and not self.tilt_event.is_set():
                    # catch frame error
                    try:
                        max = audioop.max(data, CHANNELS)
                        scaled_max = max // SCALAR
    
                        if scaled_max <= NOISE_THRESHOLD:
                            # Too quiet, ignore
                            continue
    
                        score += scaled_max / 10.0
    
                        if score > TILT_THRESHOLD:
                            self.tilt_event.set()
                            running = False
                        else:
                            self.queue.put(str(score))
    
                    except audioop.error, e:
                        if e.message != "not a whole number of frames":
                            raise e
    
    
    def main():
        GPIO.setup(BUTTON_PIN, GPIO.IN)
        stop_event = threading.Event()
        window = None
    
        try:
            root = tk.Tk()
            queue = Queue.Queue()
            window = Display(root, queue, stop_event)
    
            # Force the window to the foreground
            root.attributes('-topmost', True)
            if debug:
                root.maxsize(1920, 1200)
    
            root.mainloop()
        finally:
            stop_event.set()
            if window:
                window.audio_thread.join()
            del window
    
    
    if __name__ == '__main__':
        main()
    

There are no error messages when I run the script.

**EDIT:** It is also worth mentioning that the font size and weight are
working, just not the typeface.


Answer: I think you are missing the `Font()` construct:

    
    
    self.message_score.configure(
        text=TRY_AGAIN,
        fg=TEXT_COLOR_BODY,
        font=(TYPEFACE_AGAIN, FONT_SIZE_AGAIN, WEIGHT_AGAIN),
        pady=LINE_HEIGHT_AGAIN)
    

Instead it probably be:

    
    
    self.message_score.configure(
        text=TRY_AGAIN,
        fg=TEXT_COLOR_BODY,
        font=tkFont.Font(TYPEFACE_AGAIN, FONT_SIZE_AGAIN, WEIGHT_AGAIN),
        pady=LINE_HEIGHT_AGAIN)
    

The full version:

    
    
    #!/usr/bin/python
    
    import time
    import threading
    import Queue
    
    import Tkinter as tk
    import tkFont
    
    try:
        import alsaaudio as aa
        import audioop
        import Adafruit_BBIO.GPIO as GPIO
        debug = False
    except ImportError:
        # To enable simple testing on systems without alsa/gpio
        import mock
    
        aa = mock.MagicMock()
        aa.PCM().read.return_value = (1, '')
    
        audioop = mock.MagicMock()
        audioop.max.return_value = 5000
    
        GPIO = mock.MagicMock()
    
        import random
        GPIO.input.side_effect = lambda *a: random.randint(0, 5000) == 0
    
        debug = True
    
    # layout ########################################################
    
    BACKGROUND_COLOR = '#000000'
    
    TEXTBOX_WIDTH = 1920
    
    # vertical alignment of text in percentages from top
    
    V_ALIGN_L1 = .16
    V_ALIGN_L2 = .28
    V_ALIGN_HEADER = .52
    V_ALIGN_SCORE = .68
    V_ALIGN_TILT = .50
    V_ALIGN_AGAIN = .68
    
    # type ##########################################################
    
    TYPEFACE_L1 = 'Avenir Next Demi Bold'
    TYPEFACE_L2 = 'Avenir Next Bold'
    TYPEFACE_HEADER = 'Avenir Next Bold'
    TYPEFACE_SCORE = 'Avenir Next Demi Bold'
    TYPEFACE_TILT = 'Avenir Next Bold'
    TYPEFACE_AGAIN = 'Avenir Next Bold'
    
    WEIGHT_L1 = tkFont.NORMAL
    WEIGHT_L2 = tkFont.BOLD
    WEIGHT_HEADER = tkFont.BOLD
    WEIGHT_SCORE = tkFont.NORMAL
    WEIGHT_TILT = tkFont.BOLD
    WEIGHT_AGAIN = tkFont.BOLD
    
    FONT_SIZE_L1 = 56
    FONT_SIZE_L2 = 56
    FONT_SIZE_HEADER = 76
    FONT_SIZE_SCORE = 168
    FONT_SIZE_TILT = 114
    FONT_SIZE_AGAIN = 76
    
    LINE_HEIGHT_L1 = -5
    LINE_HEIGHT_L2 = -5
    LINE_HEIGHT_HEADER = -10
    LINE_HEIGHT_SCORE = -20
    LINE_HEIGHT_TILT = -20
    LINE_HEIGHT_AGAIN = -1
    
    TEXT_COLOR_HIGHLIGHT = '#FFFFFF'
    TEXT_COLOR_BODY = '#92C73D'
    
    # text ###########################################################
    
    L1 = 'Try to beat your own score.'
    L2 = 'The lowest score wins!'
    HEADER_MESSAGE = 'Your Score:'
    TILT_MESSAGE = 'Too loud!'
    TRY_AGAIN = 'Start again!'
    
    # audio collection configuration ##################################
    
    BUTTON_PIN = 'P8_12'
    
    DEVICE = 'hw:1'  # hardware sound card index
    CHANNELS = 2
    SAMPLE_RATE = 44100  # Hz
    PERIOD = 256  # Frames
    FORMAT = aa.PCM_FORMAT_S16_LE  # Sound format
    
    NOISE_THRESHOLD = 0  # to eliminate small noises, scale of 0 - 7
    TILT_THRESHOLD = 100.0 # upper limit of score before tilt state
    SCALAR = 4680 # normalizes score, found by trial and error
    UPDATE_TIME = 100 # ms
    
    # start script ###################################################
    
    class Display(object):
    
        def __init__(self, parent, queue, stop_event):
            self.parent = parent
            self.queue = queue
            self.stop_event = stop_event
            self.tilt_event = threading.Event()
    
            self._geom = '200x200+0+0'
            parent.geometry("{0}x{1}+0+0".format(
                parent.winfo_screenwidth(), parent.winfo_screenheight()))
            parent.overrideredirect(1)
    
            parent.title(TITLE)
            parent.configure(background=BACKGROUND_COLOR)
            self.create_text()
            self.process_queue()
    
            self.audio_thread = threading.Thread(target=self.setup_audio)
            self.audio_thread.start()
    
        def __delete__(self, instance):
            instance.stop_event.set()
    
        def create_text(self):
            message_kwargs = dict(
                bg=BACKGROUND_COLOR,
                width=TEXTBOX_WIDTH,
                justify='c',
            )
    
            self.message_L1 = tk.Message(
                self.parent,
                text=L1,
                fg=TEXT_COLOR_HIGHLIGHT,
                font=tkFont.Font(TYPEFACE_HEADER, FONT_SIZE_L1, WEIGHT_L1),
                pady=LINE_HEIGHT_L1,
                **message_kwargs)
    
            self.message_L2 = tk.Message(
                self.parent,
                text=L2,
                fg=TEXT_COLOR_HIGHLIGHT,
                font=tkFont.Font(TYPEFACE_HEADER, FONT_SIZE_L2, WEIGHT_L2),
                pady=LINE_HEIGHT_L2,
                **message_kwargs)
    
            self.message_score_header = tk.Message(
                self.parent,
                text=HEADER_MESSAGE,
                fg=TEXT_COLOR_BODY,
                font=tkFont.Font(TYPEFACE_HEADER, FONT_SIZE_HEADER, WEIGHT_HEADER),
                pady=LINE_HEIGHT_HEADER,
                **message_kwargs)
            self.message_score = tk.Message(
                self.parent,
                text='0.0',
                fg=TEXT_COLOR_HIGHLIGHT,
                font=tkFont.Font(TYPEFACE_SCORE, FONT_SIZE_SCORE, WEIGHT_SCORE),
                pady=LINE_HEIGHT_SCORE,
                **message_kwargs)
    
            self.message_L1.place(relx=.5, rely=V_ALIGN_L1, anchor='c')
            self.message_L2.place(relx=.5, rely=V_ALIGN_L2, anchor='c')
            self.message_score_header.place(relx=V_ALIGN_HEADER, rely=.5, anchor='c')
            self.message_score.place(relx=.5, rely=V_ALIGN_SCORE, anchor='c')
    
        def process_queue(self):
            text = None
            while not self.queue.empty():
                text = self.queue.get_nowait()
    
            if text:
                self.message_score_header.configure(text=HEADER_MESSAGE)
                self.message_score.configure(text=text)
            elif self.tilt_event.is_set():
                self.message_L1.configure(text="")
                self.message_L2.configure(text="")
                self.message_score_header.configure(
                    text=TILT_MESSAGE,
                    fg=TEXT_COLOR_HIGHLIGHT,
                    font=tkFont.Font(
                        TYPEFACE_TILT,
                        FONT_SIZE_TILT,
                        WEIGHT_TILT,
                    ),
                    pady=LINE_HEIGHT_TILT)
                self.message_score.configure(
                    text=TRY_AGAIN,
                    fg=TEXT_COLOR_BODY,
                    font=tkFont.Font(
                        TYPEFACE_AGAIN,
                        FONT_SIZE_AGAIN,
                        WEIGHT_AGAIN,
                    ),
                    pady=LINE_HEIGHT_AGAIN)
                self.message_score.place(relx=.75, rely=V_ALIGN_AGAIN, anchor='c')
    
            self.parent.after(UPDATE_TIME, self.process_queue)
    
        def setup_audio(self):
            data_in = aa.PCM(aa.PCM_CAPTURE, aa.PCM_NONBLOCK, DEVICE)
            data_in.setchannels(2)
            data_in.setrate(SAMPLE_RATE)
            data_in.setformat(FORMAT)
    
            data_in.setperiodsize(PERIOD)
    
            score = 0
            running = False
    
            while not self.stop_event.is_set():
                # Sleep a very short time to prevent the thread from locking up
                time.sleep(0.001)
    
                if GPIO.input(BUTTON_PIN):
                    self.tilt_event.clear()
                    score = 0
                    if not running:
                        self.message_L1.configure(text=L1)
                        self.message_L2.configure(text=L2)
                        self.message_score_header.configure(
                            text=HEADER_MESSAGE,
                            fg=TEXT_COLOR_BODY,
                            font=tkFont.Font(
                                TYPEFACE_HEADER,
                                FONT_SIZE_HEADER,
                                WEIGHT_HEADER,
                            ),
                            pady=LINE_HEIGHT_HEADER)
                        self.message_score.configure(
                            text='0.0',
                            fg=TEXT_COLOR_HIGHLIGHT,
                            font=tkFont.Font(
                                TYPEFACE_SCORE,
                                FONT_SIZE_SCORE,
                                WEIGHT_SCORE,
                            ),
                            pady=LINE_HEIGHT_SCORE)
                        self.message_score.place(
                            relx=.5,
                            rely=V_ALIGN_SCORE,
                            anchor='c')
    
                        running = True
                    self.queue.put('0.0')
                elif not running:
                    # Not running yet, keep waiting
                    continue
    
                # Read data from device
                l, data = data_in.read()
                if l and not self.tilt_event.is_set():
                    # catch frame error
                    try:
                        max = audioop.max(data, CHANNELS)
                        scaled_max = max // SCALAR
    
                        if scaled_max <= NOISE_THRESHOLD:
                            # Too quiet, ignore
                            continue
    
                        score += scaled_max / 10.0
    
                        if score > TILT_THRESHOLD:
                            self.tilt_event.set()
                            running = False
                        else:
                            self.queue.put(str(score))
    
                    except audioop.error, e:
                        if e.message != "not a whole number of frames":
                            raise e
    
    
    def main():
        GPIO.setup(BUTTON_PIN, GPIO.IN)
        stop_event = threading.Event()
        window = None
    
        try:
            root = tk.Tk()
            queue = Queue.Queue()
            window = Display(root, queue, stop_event)
    
            # Force the window to the foreground
            root.attributes('-topmost', True)
            if debug:
                root.maxsize(1920, 1200)
    
            root.mainloop()
        finally:
            stop_event.set()
            if window:
                window.audio_thread.join()
            del window
    
    
    if __name__ == '__main__':
        main()
    
    There are no error messages when I run the script.
    

