Daniel Huckson
Daniel Huckson

Reputation: 1247

Tkinter how to change treeview font

I'm trying to change the font in a tkinter treeview but can't figure out how to do it. I can change the treeview column header font but not the font in the rows. The demo below uses a spinbox to change the font size. I have tried using "TkTextFont" but it didn't work, it changes the font size in the spinbox but not the treeview..

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.font as tkfont


class MySpinbox(ttk.Spinbox):
    def __init__(self, master=None, delay=250, **kwargs):
        ttk.Spinbox.__init__(self, master, **kwargs)
        self.delay = delay  # repeatdelay in ms
        self.bind('<<Increment>>', self._on_increment)
        self.bind('<<Decrement>>', self._on_decrement)
        self._increment_lock = False
        self._decrement_lock = False

    def _unlock_increment(self):
        self._increment_lock = False

    def _on_increment(self, event):
        if self._increment_lock:
            return "break"  # stop the increment
        else:
            # generate a virtual event corresponding to when the spinbox
            # is actually incremented
            self.event_generate('<<ActualIncrement>>')
            self._increment_lock = True
            self.after(self.delay, self._unlock_increment)

    def _unlock_decrement(self):
        self._decrement_lock = False

    def _on_decrement(self, event):
        if self._decrement_lock:
            return "break"  # stop the increment
        else:
            # generate a virtual event corresponding to when the spinbox
            # is actually decremented
            self.event_generate('<<ActualDecrement>>')
            self._decrement_lock = True
            self.after(self.delay, self._unlock_decrement)


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.title('Treeview Demo')
        self.geometry('420x200+20+20')

        style = ttk.Style()

        var = tk.StringVar()
        var.set(9)

        tv = self.tv = ttk.Treeview(self)
        tv.grid(row=0, column=0, sticky='NSEW')

        def size():
            font = tkfont.nametofont('TkHeadingFont')
            font.config(size=var.get())
            style.configure('Treeview.Heading', font=font)

            font = tkfont.nametofont('TkTextFont')
            font.config(size=var.get())

        spn = MySpinbox(self, textvariable=var, values=list(range(0, 1000)), command=size)
        spn.grid(row=0, column=1, pady=5, padx=20)

        tv.heading('#0', text='Name')

        tv.insert('', '0', 'item1', text='Item 1')
        tv.insert('', '1', 'item2', text='Item 2')
        tv.insert('', '2', 'item3', text='Item 3')

        tv.insert('item1', '0', 'python1', text='Python 1')
        tv.insert('item1', '1', 'python2', text='Python 2')

        tv.insert('python1', '0', 'sub1', text='Sub item 1')
        tv.insert('python1', '1', 'sub2', text='Sub item 2')


def main():
    app = App()
    app.mainloop()


if __name__ == '__main__':
    main()

Upvotes: 2

Views: 6155

Answers (2)

Daniel Huckson
Daniel Huckson

Reputation: 1247

I just figured out how to set the font in a treeview and I'm posting my solution here, case someone else has the same problem. It seems that treeview doesn't respond to named fonts, you have to configure tags using treeview.tag_configure() and set the tags argument when inserting items in the tree. I think this is the only way to do it.

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.font as tkfont


class MySpinbox(ttk.Spinbox):
    def __init__(self, master=None, delay=100, **kwargs):
        ttk.Spinbox.__init__(self, master, **kwargs)
        self.delay = delay  # repeatdelay in ms
        self.bind('<<Increment>>', self._on_increment)
        self.bind('<<Decrement>>', self._on_decrement)
        self._increment_lock = False
        self._decrement_lock = False

    def _unlock_increment(self):
        self._increment_lock = False

    def _on_increment(self, event):
        if self._increment_lock:
            return "break"  # stop the increment
        else:
            # generate a virtual event corresponding to when the spinbox
            # is actually incremented
            self.event_generate('<<ActualIncrement>>')
            self._increment_lock = True
            self.after(self.delay, self._unlock_increment)

    def _unlock_decrement(self):
        self._decrement_lock = False

    def _on_decrement(self, event):
        if self._decrement_lock:
            return "break"  # stop the increment
        else:
            # generate a virtual event corresponding to when the spinbox
            # is actually decremented
            self.event_generate('<<ActualDecrement>>')
            self._decrement_lock = True
            self.after(self.delay, self._unlock_decrement)


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.title('Treeview Demo')
        self.geometry('420x200+20+20')

        style = ttk.Style()

        var = tk.StringVar()
        var.set(9)

        tv = self.tv = ttk.Treeview(self)
        tv.grid(row=0, column=0, sticky='NSEW')

        font = tkfont.nametofont('TkTextFont')
        tv.tag_configure('TkTextFont', font=tkfont.nametofont('TkTextFont'))
        style.configure('Treeview', rowheight=font.metrics('linespace'))

        def size():
            _font = tkfont.nametofont('TkHeadingFont')
            _font.config(size=var.get())
            style.configure('Treeview.Heading', font=_font)

            _font = tkfont.nametofont('TkTextFont')
            _font.configure(size=var.get())
            style.configure('Treeview', rowheight=_font.metrics('linespace'))

        spn = MySpinbox(self, textvariable=var, values=list(range(0, 1000)), command=size)
        spn.grid(row=0, column=1, pady=5, padx=20)

        tv.heading('#0', text='Name')

        tv.insert('', '0', 'item1', text='Item 1', tags='TkTextFont')
        tv.insert('', '1', 'item2', text='Item 2', tags='TkTextFont')
        tv.insert('', '2', 'item3', text='Item 3', tags='TkTextFont')

        tv.insert('item1', '0', 'python1', text='Python 1', tags='TkTextFont')
        tv.insert('item1', '1', 'python2', text='Python 2', tags='TkTextFont')

        tv.insert('python1', '0', 'sub1', text='Sub item 1', tags='TkTextFont')
        tv.insert('python1', '1', 'sub2', text='Sub item 2', tags='TkTextFont')


def main():
    app = App()
    app.mainloop()


if __name__ == '__main__':
    main()

Upvotes: 2

Richard Parkins
Richard Parkins

Reputation: 528

It probably does respond to named fonts, but you have to guess the right name.

tk.splitlist(tk.call("font", "names"))

will get you a list of the names it uses. Then you can try changing the size of each one to find out which one it uses.

Upvotes: 0

Related Questions