RobertJN64 / TKinterModernThemes

A collection of modern themes with code that makes it easy to integrate into a tkinter project.
MIT License
91 stars 7 forks source link

Custom Font #4

Closed Asleep123 closed 7 months ago

Asleep123 commented 8 months ago

How would I change the font for a theme? I tried going into the azure.tcl file and changing the font name, but I don't think anything changed.

RobertJN64 commented 8 months ago

I typically just set the font inside the code. Some widgets allow for a font parameter (either in the function args or in the **widgetkwargs), but most widgets just use the current font set by the theme. This is a limitation of tk vs tkk.

import TKinterModernThemes as TKMT
from tkinter import ttk

class App(TKMT.ThemedTKinterFrame):
    def __init__(self):
        super().__init__("Font Demo")

        s = ttk.Style()
        s.configure('.', font=('Courier',20))  # change default font
Asleep123 commented 8 months ago

You can’t do it from a font file?

RobertJN64 commented 8 months ago

You can - just make sure you edit both locations in the theme.tcl file. For azure.tcl, that is line 31 for dark and line 70 for light.

For example, -font {"Courier" 20} \ changes to a larger monospaced font.

(Typically I don't like editing library files because they will be overwritten when the library is updated. If you need to define font outside code, the best option is probably writing your own logic to open a file, read the font, and call the .configure code above).

Asleep123 commented 8 months ago

I mean like as in a .ttf file to the font.

RobertJN64 commented 8 months ago

OK - that is a tkinter question - TKMT doesn't do anything special with fonts.

Here is some info: https://stackoverflow.com/questions/11993290/truly-custom-font-in-tkinter

Looks like pyglet or tkextrafont might be helpful.

Asleep123 commented 8 months ago

It seems like when I set it using ttk.Style(), it only works on the window titles, and nothing else. Also, is there a way to use a Listbox? It doesn't seem to exist in the WidgetFrame class. image

RobertJN64 commented 8 months ago

ttk.Style() will apply to all ttk widgets. For some reason, Labels do not obey this and must be set separately (possibly because TKMT customizes other aspects of the label font.)

Here is some example code showing different cases:

import TKinterModernThemes as TKMT
from tkinter import ttk

class App(TKMT.ThemedTKinterFrame):
    def __init__(self, theme, mode, usecommandlineargs=True, usethemeconfigfile=True):
        super().__init__("Font Demo", theme, mode,
                         usecommandlineargs=usecommandlineargs, useconfigfile=usethemeconfigfile)

        s = ttk.Style()
        s.configure('.', font=('Courier', 20))  # change default font
        s.configure('my_custom_style.TButton', font=('Helvetica', 12))

        self.frame = self.addLabelFrame("This uses ttk style")
        self.frame.Text("This uses ttk style")
        self.frame.Text("This uses fontargs", fontargs=('-family', 'MS Serif'))

        self.frame.Label("This doesn't obey ttk style")
        self.frame.Label("But can be set with fontargs", fontargs=('-family', 'MS Serif'))

        self.frame.Button("This always obeys ttk style", command=None)

        cust_button = self.frame.Button("Unless you set a custom style", command=None)
        cust_button.configure(style='my_custom_style.TButton')

        self.run()

if __name__ == "__main__":
    App("park", "dark")

Which results in this: image

If expect / need something to behave differently please send the code you are running and the result you expect.

I am checking if Listbox can be supported - it is not included in the ttk widgets or the themes I use, but still might be possible.

RobertJN64 commented 8 months ago

Because Listbox isn't a ttk widget I am not going to add it to WidgetFrame - however you can still use it in a TKMT project.

from TKinterModernThemes.WidgetFrame import Widget
import TKinterModernThemes as TKMT
import tkinter as tk

class App(TKMT.ThemedTKinterFrame):
    def __init__(self, theme, mode, usecommandlineargs=True, usethemeconfigfile=True):
        super().__init__("Listbox", theme, mode,
                         usecommandlineargs=usecommandlineargs, useconfigfile=usethemeconfigfile)

        choices = ["apple", "orange", "banana"]
        choicesvar = tk.StringVar(value=choices)
        self.frame = self.addLabelFrame("Listbox Frame")

        widget = tk.Listbox(self.frame.master, listvariable=choicesvar, selectmode=tk.MULTIPLE)
        widget.grid(row=0, column=0, padx=10, pady=10, sticky='ew', rowspan=1, columnspan=1)
        self.frame.widgets.append(Widget(widget, "Listbox", 0, 0, 1, 1))
        self.debugPrint()
        self.run()

if __name__ == "__main__":
    App("park", "dark")

However, I would highly recommend using the Treeview widget instead.

import TKinterModernThemes as TKMT

class App(TKMT.ThemedTKinterFrame):
    def __init__(self, theme, mode, usecommandlineargs=True, usethemeconfigfile=True):
        super().__init__("Treeview", theme, mode,
                         usecommandlineargs=usecommandlineargs, useconfigfile=usethemeconfigfile)

        tree_data = [
            {"fruit": "apple"},
            {"fruit": "orange"},
            {"fruit": "lemon"},
        ]

        self.frame = self.addLabelFrame("Treeview Frame")
        self.treeview_widget = self.frame.Treeview(['Fruit'], [120], 10, tree_data, None, ['fruit'])
        self.frame.AccentButton("Print Selected Items", self.print_selected_cmd)

        self.run()

    def print_selected_cmd(self):
        print("Currently selected:", self.treeview_widget.selection())
        for item in self.treeview_widget.selection():
            print('--', self.treeview_widget.item(item))

if __name__ == "__main__":
    App("park", "dark")
Currently selected: ()
Currently selected: ('3',)
-- {'text': 'lemon', 'image': '', 'values': '', 'open': 0, 'tags': ''}
Currently selected: ('1', '3')
-- {'text': 'apple', 'image': '', 'values': '', 'open': 0, 'tags': ''}
-- {'text': 'lemon', 'image': '', 'values': '', 'open': 0, 'tags': ''}