From 1b28a9cff89c354d53a72b01453bb61f22d006b4 Mon Sep 17 00:00:00 2001 From: kurawlefaraaz <70267324+kurawlefaraaz@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:39:16 +0530 Subject: [PATCH 1/4] Delete tkfontchooser.py --- tkfontchooser.py | 556 ----------------------------------------------- 1 file changed, 556 deletions(-) delete mode 100755 tkfontchooser.py diff --git a/tkfontchooser.py b/tkfontchooser.py deleted file mode 100755 index 79a851e..0000000 --- a/tkfontchooser.py +++ /dev/null @@ -1,556 +0,0 @@ -# -*- coding: utf-8 -*- -""" -tkFontChooser - Font chooser for Tkinter -Copyright 2016-2017 Juliette Monsel - -tkFontChooser is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -tkFontChooser is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" - -try: - from tkinter import Toplevel, Listbox, StringVar, BooleanVar, TclError - from tkinter.ttk import Checkbutton, Frame, Label, Button, Scrollbar, Style, Entry - from tkinter.font import families, Font -except ImportError: - from Tkinter import Toplevel, Listbox, StringVar, BooleanVar - from ttk import Checkbutton, Frame, Label, Button, Scrollbar, Style, Entry - from tkFont import families, Font - -from locale import getdefaultlocale - -__version__ = "2.0.2" - -# --- translation -EN = {"Cancel": "Cancel", "Bold": "Bold", "Italic": "Italic", - "Underline": "Underline", "Overstrike": "Strikethrough"} -FR = {"Cancel": "Annuler", "Bold": "Gras", "Italic": "Italique", - "Underline": "Souligné", "Overstrike": "Barré"} -IT = {"Cancel": "Annulla", "Bold": "Grassetto", "Italic": "Corsivo", - "Underline": "Sottolineato", "Overstrike": "Barrato"} -RU = {"Cancel": "Отмена", "Bold": "Полужирный", "Italic": "Курсив", - "Underline": "Подчеркнутый", "Overstrike": "Зачеркнутый"} -LANGUAGES = {"fr": FR, "en": EN, "it": IT, "ru": RU} - -try: - lang_code = getdefaultlocale()[0][:2] - if lang_code in LANGUAGES: - TR = LANGUAGES[lang_code] - else: - TR = LANGUAGES["en"] - -except ValueError: - TR = LANGUAGES["en"] - - -# --- FontChooser class -class FontChooser(Toplevel): - """Font chooser dialog.""" - - def __init__(self, master, font_dict={}, text="Abcd", title="Font Chooser", - **kwargs): - """ - Create a new FontChooser instance. - - Arguments: - - master : Tk or Toplevel instance - master window - - font_dict : dict - dictionnary, like the one returned by the ``actual`` method of a ``Font`` object: - - :: - - {'family': str, - 'size': int, - 'weight': 'bold'/'normal', - 'slant': 'italic'/'roman', - 'underline': bool, - 'overstrike': bool} - - text : str - text to be displayed in the preview label - - title : str - window title - - kwargs : dict - additional keyword arguments to be passed to ``Toplevel.__init__`` - """ - Toplevel.__init__(self, master, **kwargs) - self.title(title) - self.resizable(False, False) - self.protocol("WM_DELETE_WINDOW", self.quit) - self._validate_family = self.register(self.validate_font_family) - self._validate_size = self.register(self.validate_font_size) - - # --- variable storing the chosen font - self.res = "" - - style = Style(self) - style.configure("prev.TLabel", background="white") - bg = style.lookup("TLabel", "background") - self.configure(bg=bg) - - # --- family list - self.fonts = list(set(families())) - self.fonts.append("TkDefaultFont") - self.fonts.sort() - for i in range(len(self.fonts)): - self.fonts[i] = self.fonts[i].replace(" ", "\ ") - max_length = int(2.5 * max([len(font) for font in self.fonts])) // 3 - self.sizes = ["%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2)))] - # --- font default - font_dict["weight"] = font_dict.get("weight", "normal") - font_dict["slant"] = font_dict.get("slant", "roman") - font_dict["underline"] = font_dict.get("underline", False) - font_dict["overstrike"] = font_dict.get("overstrike", False) - font_dict["family"] = font_dict.get("family", - self.fonts[0].replace('\ ', ' ')) - font_dict["size"] = font_dict.get("size", 10) - - # --- creation of the widgets - # ------ style parameters (bold, italic ...) - options_frame = Frame(self, relief='groove', borderwidth=2) - self.font_family = StringVar(self, " ".join(self.fonts)) - self.font_size = StringVar(self, " ".join(self.sizes)) - self.var_bold = BooleanVar(self, font_dict["weight"] == "bold") - b_bold = Checkbutton(options_frame, text=TR["Bold"], - command=self.toggle_bold, - variable=self.var_bold) - b_bold.grid(row=0, sticky="w", padx=4, pady=(4, 2)) - self.var_italic = BooleanVar(self, font_dict["slant"] == "italic") - b_italic = Checkbutton(options_frame, text=TR["Italic"], - command=self.toggle_italic, - variable=self.var_italic) - b_italic.grid(row=1, sticky="w", padx=4, pady=2) - self.var_underline = BooleanVar(self, font_dict["underline"]) - b_underline = Checkbutton(options_frame, text=TR["Underline"], - command=self.toggle_underline, - variable=self.var_underline) - b_underline.grid(row=2, sticky="w", padx=4, pady=2) - self.var_overstrike = BooleanVar(self, font_dict["overstrike"]) - b_overstrike = Checkbutton(options_frame, text=TR["Overstrike"], - variable=self.var_overstrike, - command=self.toggle_overstrike) - b_overstrike.grid(row=3, sticky="w", padx=4, pady=(2, 4)) - # ------ Size and family - self.var_size = StringVar(self) - self.entry_family = Entry(self, width=max_length, validate="key", - validatecommand=(self._validate_family, "%d", "%S", - "%i", "%s", "%V")) - self.entry_size = Entry(self, width=4, validate="key", - textvariable=self.var_size, - validatecommand=(self._validate_size, "%d", "%P", "%V")) - self.list_family = Listbox(self, selectmode="browse", - listvariable=self.font_family, - highlightthickness=0, - exportselection=False, - width=max_length) - self.list_size = Listbox(self, selectmode="browse", - listvariable=self.font_size, - highlightthickness=0, - exportselection=False, - width=4) - scroll_family = Scrollbar(self, orient='vertical', - command=self.list_family.yview) - scroll_size = Scrollbar(self, orient='vertical', - command=self.list_size.yview) - self.preview_font = Font(self, **font_dict) - if len(text) > 30: - text = text[:30] - self.preview = Label(self, relief="groove", style="prev.TLabel", - text=text, font=self.preview_font, - anchor="center") - - # --- widget configuration - self.list_family.configure(yscrollcommand=scroll_family.set) - self.list_size.configure(yscrollcommand=scroll_size.set) - - self.entry_family.insert(0, font_dict["family"]) - self.entry_family.selection_clear() - self.entry_family.icursor("end") - self.entry_size.insert(0, font_dict["size"]) - - try: - i = self.fonts.index(self.entry_family.get().replace(" ", "\ ")) - except ValueError: - # unknown font - i = 0 - self.list_family.selection_clear(0, "end") - self.list_family.selection_set(i) - self.list_family.see(i) - try: - i = self.sizes.index(self.entry_size.get()) - self.list_size.selection_clear(0, "end") - self.list_size.selection_set(i) - self.list_size.see(i) - except ValueError: - # size not in list - pass - - self.entry_family.grid(row=0, column=0, sticky="ew", - pady=(10, 1), padx=(10, 0)) - self.entry_size.grid(row=0, column=2, sticky="ew", - pady=(10, 1), padx=(10, 0)) - self.list_family.grid(row=1, column=0, sticky="nsew", - pady=(1, 10), padx=(10, 0)) - self.list_size.grid(row=1, column=2, sticky="nsew", - pady=(1, 10), padx=(10, 0)) - scroll_family.grid(row=1, column=1, sticky='ns', pady=(1, 10)) - scroll_size.grid(row=1, column=3, sticky='ns', pady=(1, 10)) - options_frame.grid(row=0, column=4, rowspan=2, - padx=10, pady=10, ipadx=10) - - self.preview.grid(row=2, column=0, columnspan=5, sticky="eswn", - padx=10, pady=(0, 10), ipadx=4, ipady=4) - - button_frame = Frame(self) - button_frame.grid(row=3, column=0, columnspan=5, pady=(0, 10), padx=10) - - Button(button_frame, text="Ok", - command=self.ok).grid(row=0, column=0, padx=4, sticky='ew') - Button(button_frame, text=TR["Cancel"], - command=self.quit).grid(row=0, column=1, padx=4, sticky='ew') - self.list_family.bind('<>', self.update_entry_family) - self.list_size.bind('<>', self.update_entry_size, - add=True) - self.list_family.bind("", self.keypress) - self.entry_family.bind("", self.change_font_family) - self.entry_family.bind("", self.tab) - self.entry_size.bind("", self.change_font_size) - - self.entry_family.bind("", self.down_family) - self.entry_size.bind("", self.down_size) - - self.entry_family.bind("", self.up_family) - self.entry_size.bind("", self.up_size) - - # bind Ctrl+A to select all instead of go to beginning - self.bind_class("TEntry", "", self.select_all) - - self.wait_visibility(self) - self.grab_set() - self.entry_family.focus_set() - self.lift() - - def select_all(self, event): - """Select all entry content.""" - event.widget.selection_range(0, "end") - - def keypress(self, event): - """Select the first font whose name begin by the key pressed.""" - key = event.char.lower() - l = [i for i in self.fonts if i[0].lower() == key] - if l: - i = self.fonts.index(l[0]) - self.list_family.selection_clear(0, "end") - self.list_family.selection_set(i) - self.list_family.see(i) - self.update_entry_family() - - def up_family(self, event): - """Navigate in the family listbox with up key.""" - try: - i = self.list_family.curselection()[0] - self.list_family.selection_clear(0, "end") - if i <= 0: - i = len(self.fonts) - self.list_family.see(i - 1) - self.list_family.select_set(i - 1) - except TclError: - self.list_family.selection_clear(0, "end") - i = len(self.fonts) - self.list_family.see(i - 1) - self.list_family.select_set(i - 1) - self.list_family.event_generate('<>') - - def up_size(self, event): - """Navigate in the size listbox with up key.""" - try: - s = self.var_size.get() - if s in self.sizes: - i = self.sizes.index(s) - elif s: - sizes = list(self.sizes) - sizes.append(s) - sizes.sort(key=lambda x: int(x)) - i = sizes.index(s) - else: - i = 0 - self.list_size.selection_clear(0, "end") - if i <= 0: - i = len(self.sizes) - self.list_size.see(i - 1) - self.list_size.select_set(i - 1) - except TclError: - i = len(self.sizes) - self.list_size.see(i - 1) - self.list_size.select_set(i - 1) - self.list_size.event_generate('<>') - - def down_family(self, event): - """Navigate in the family listbox with down key.""" - try: - i = self.list_family.curselection()[0] - self.list_family.selection_clear(0, "end") - if i >= len(self.fonts): - i = -1 - self.list_family.see(i + 1) - self.list_family.select_set(i + 1) - except TclError: - self.list_family.selection_clear(0, "end") - self.list_family.see(0) - self.list_family.select_set(0) - self.list_family.event_generate('<>') - - def down_size(self, event): - """Navigate in the size listbox with down key.""" - try: - s = self.var_size.get() - if s in self.sizes: - i = self.sizes.index(s) - elif s: - sizes = list(self.sizes) - sizes.append(s) - sizes.sort(key=lambda x: int(x)) - i = sizes.index(s) - 1 - else: - s = len(self.sizes) - 1 - self.list_size.selection_clear(0, "end") - if i < len(self.sizes) - 1: - self.list_size.selection_set(i + 1) - self.list_size.see(i + 1) - else: - self.list_size.see(0) - self.list_size.select_set(0) - except TclError: - self.list_size.selection_set(0) - self.list_size.event_generate('<>') - - def toggle_bold(self): - """Update font preview weight.""" - b = self.var_bold.get() - self.preview_font.configure(weight=["normal", "bold"][b]) - - def toggle_italic(self): - """Update font preview slant.""" - b = self.var_italic.get() - self.preview_font.configure(slant=["roman", "italic"][b]) - - def toggle_underline(self): - """Update font preview underline.""" - b = self.var_underline.get() - self.preview_font.configure(underline=b) - - def toggle_overstrike(self): - """Update font preview overstrike.""" - b = self.var_overstrike.get() - self.preview_font.configure(overstrike=b) - - def change_font_family(self, event=None): - """Update font preview family.""" - family = self.entry_family.get() - if family.replace(" ", "\ ") in self.fonts: - self.preview_font.configure(family=family) - - def change_font_size(self, event=None): - """Update font preview size.""" - size = int(self.var_size.get()) - self.preview_font.configure(size=size) - - def validate_font_size(self, d, ch, V): - """Validation of the size entry content.""" - l = [i for i in self.sizes if i[:len(ch)] == ch] - i = None - if l: - i = self.sizes.index(l[0]) - elif ch.isdigit(): - sizes = list(self.sizes) - sizes.append(ch) - sizes.sort(key=lambda x: int(x)) - i = min(sizes.index(ch), len(self.sizes)) - if i is not None: - self.list_size.selection_clear(0, "end") - self.list_size.selection_set(i) - deb = self.list_size.nearest(0) - fin = self.list_size.nearest(self.list_size.winfo_height()) - if V != "forced": - if i < deb or i > fin: - self.list_size.see(i) - return True - if d == '1': - return ch.isdigit() - else: - return True - - def tab(self, event): - """Move at the end of selected text on tab press.""" - self.entry_family = event.widget - self.entry_family.selection_clear() - self.entry_family.icursor("end") - return "break" - - def validate_font_family(self, action, modif, pos, prev_txt, V): - """Completion of the text in the entry with existing font names.""" - if self.entry_family.selection_present(): - sel = self.entry_family.selection_get() - txt = prev_txt.replace(sel, '') - else: - txt = prev_txt - if action == "0": - txt = txt[:int(pos)] + txt[int(pos) + 1:] - return True - else: - txt = txt[:int(pos)] + modif + txt[int(pos):] - ch = txt.replace(" ", "\ ") - l = [i for i in self.fonts if i[:len(ch)] == ch] - if l: - i = self.fonts.index(l[0]) - self.list_family.selection_clear(0, "end") - self.list_family.selection_set(i) - deb = self.list_family.nearest(0) - fin = self.list_family.nearest(self.list_family.winfo_height()) - index = self.entry_family.index("insert") - self.entry_family.delete(0, "end") - self.entry_family.insert(0, l[0].replace("\ ", " ")) - self.entry_family.selection_range(index + 1, "end") - self.entry_family.icursor(index + 1) - if V != "forced": - if i < deb or i > fin: - self.list_family.see(i) - return True - else: - return False - - def update_entry_family(self, event=None): - """Update family entry when an item is selected in the family listbox.""" - # family = self.list_family.get("@%i,%i" % (event.x , event.y)) - family = self.list_family.get(self.list_family.curselection()[0]) - self.entry_family.delete(0, "end") - self.entry_family.insert(0, family) - self.entry_family.selection_clear() - self.entry_family.icursor("end") - self.change_font_family() - - def update_entry_size(self, event): - """Update size entry when an item is selected in the size listbox.""" - # size = self.list_size.get("@%i,%i" % (event.x , event.y)) - size = self.list_size.get(self.list_size.curselection()[0]) - self.var_size.set(size) - self.change_font_size() - - def ok(self): - """Validate choice.""" - self.res = self.preview_font.actual() - self.quit() - - def get_res(self): - """Return chosen font.""" - return self.res - - def quit(self): - self.destroy() - - -def askfont(master=None, text="Abcd", title="Font Chooser", **font_args): - """ - Open the font chooser and return a dictionary of the font properties. - - General Arguments: - - master : Tk or Toplevel instance - master window - - text : str - sample text to be displayed in the font chooser - - title : str - dialog title - - Font arguments: - - family : str - font family - - size : int - font size - - slant : str - "roman" or "italic" - - weight : str - "normal" or "bold" - - underline : bool - whether the text is underlined - - overstrike : bool - whether the text is overstriked - - Output: - - dictionary is similar to the one returned by the ``actual`` method of a tkinter ``Font`` object: - - :: - - {'family': str, - 'size': int, - 'weight': 'bold'/'normal', - 'slant': 'italic'/'roman', - 'underline': bool, - 'overstrike': bool} - - """ - chooser = FontChooser(master, font_args, text, title) - chooser.wait_window(chooser) - return chooser.get_res() - - -if __name__ == "__main__": - """Example.""" - try: - from tkinter import Tk - except ImportError: - from Tkinter import Tk - from sys import platform - - root = Tk() - style = Style(root) - if "win" == platform[:3]: - style.theme_use('vista') - elif "darwin" in platform: - style.theme_use('clam') - else: - style.theme_use('clam') - bg = style.lookup("TLabel", "background") - root.configure(bg=bg) - label = Label(root, text='Chosen font: ') - label.pack(padx=10, pady=(10, 4)) - - def callback(): - font = askfont(root, title="Choose a font") - if font: - # spaces in the family name need to be escaped - font['family'] = font['family'].replace(' ', '\ ') - font_str = "%(family)s %(size)i %(weight)s %(slant)s" % font - if font['underline']: - font_str += ' underline' - if font['overstrike']: - font_str += ' overstrike' - label.configure(font=font_str, - text='Chosen font: ' + font_str.replace('\ ', ' ')) - - Button(root, text='Font Chooser', - command=callback).pack(padx=10, pady=(4, 10)) - root.mainloop() From 6efa9ad36f951d128adec9a080c90b3a98e5cece Mon Sep 17 00:00:00 2001 From: kurawlefaraaz <70267324+kurawlefaraaz@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:40:08 +0530 Subject: [PATCH 2/4] Delete test.py --- test.py | 166 -------------------------------------------------------- 1 file changed, 166 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index 522c6d4..0000000 --- a/test.py +++ /dev/null @@ -1,166 +0,0 @@ -# -*- coding: utf-8 -*- -""" -tkFontChooser - Font chooser for Tkinter -Copyright 2016-2017 Juliette Monsel - -tkFontChooser is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -tkFontChooser is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -Tests -""" - -import unittest -from tkfontchooser import FontChooser, askfont -try: - import Tkinter as tk - import ttk - import tkFont -except ImportError: - import tkinter as tk - from tkinter import ttk - from tkinter import font as tkFont -import logging - - -class BaseWidgetTest(unittest.TestCase): - def setUp(self): - logging.basicConfig(filename='/tmp/test.log', level=logging.DEBUG) - self.window = tk.Toplevel() - self.window.update() - - def tearDown(self): - self.window.update() - self.window.destroy() - - -class TestEvent: - """Fake event for testing.""" - def __init__(self, **kwargs): - self._prop = kwargs - - def __getattr__(self, attr): - if attr not in self._prop: - raise AttributeError("TestEvent has no attribute %s." % attr) - else: - return self._prop[attr] - - -class TestFontChooser(BaseWidgetTest): - def test_fontchooser_init(self): - FontChooser(self.window, - {'family': 'Arial', 'weight': 'bold', 'slant': 'italic'}, - text='Abcd' * 20, title='Test') - self.window.update() - - def test_fontchooser_methods(self): - props = {'family': "TkDefaultFont", 'weight': 'bold', 'size': 27, - 'slant': 'italic'} - fc = FontChooser(self.window, props) - self.window.update() - - e = ttk.Entry(self.window) - e.insert(0, 'abcd') - fc.select_all(TestEvent(widget=e)) - self.assertEqual(e.selection_get(), 'abcd') - - self.assertEqual(fc.get_res(), "") - fc.ok() - self.window.update() - font = tkFont.Font(self.window, **props) - self.assertEqual(fc.get_res(), font.actual()) - # ok() destroys the toplevel - fc = FontChooser(self.window, {'family': "TkDefaultFont", "size": 20}) - self.window.update() - i = fc.list_family.curselection()[0] - self.assertEqual(fc.fonts[i], "TkDefaultFont") - - self.assertEqual(fc.preview_font.actual()['weight'], "normal") - fc.var_bold.set(True) - fc.toggle_bold() - self.window.update() - self.assertEqual(fc.preview_font.actual()['weight'], "bold") - - self.assertEqual(fc.preview_font.actual()['slant'], "roman") - fc.var_italic.set(True) - fc.toggle_italic() - self.window.update() - self.assertEqual(fc.preview_font.actual()['slant'], "italic") - - self.assertEqual(fc.preview_font.actual()['underline'], False) - fc.var_underline.set(True) - fc.toggle_underline() - self.window.update() - self.assertEqual(fc.preview_font.actual()['underline'], True) - - self.assertEqual(fc.preview_font.actual()['overstrike'], False) - fc.var_overstrike.set(True) - fc.toggle_overstrike() - self.window.update() - self.assertEqual(fc.preview_font.actual()['overstrike'], True) - fc.up_family(None) - self.window.update() - self.assertEqual(fc.list_family.curselection()[0], i - 1) - fc.down_family(None) - self.window.update() - self.assertEqual(fc.list_family.curselection()[0], i) - - i = fc.list_size.curselection()[0] - self.assertEqual(fc.sizes[i], '20') - fc.up_size(None) - self.window.update() - self.assertEqual(fc.list_size.curselection()[0], i - 1) - fc.down_size(None) - self.window.update() - self.assertEqual(fc.list_size.curselection()[0], i) - - fc.entry_size.delete(0, 'end') - fc.entry_size.insert(0, '17') - i = fc.list_size.curselection()[0] - self.assertEqual(fc.sizes[i], '18') - fc.up_size(None) - self.window.update() - self.assertEqual(fc.sizes[fc.list_size.curselection()[0]], '16') - self.assertEqual(fc.entry_size.get(), '16') - fc.entry_size.delete(0, 'end') - fc.entry_size.insert(0, '17') - fc.down_size(None) - self.window.update() - self.assertEqual(fc.sizes[fc.list_size.curselection()[0]], '18') - self.assertEqual(fc.entry_size.get(), '18') - - fc.keypress(TestEvent(char=fc.fonts[0][0])) - self.assertEqual(fc.list_family.curselection()[0], 0) - - def test_askfont(self): - - def test(event): - event.widget.ok() - fontprops = event.widget.get_res() - self.assertEqual(fontprops['size'], 20) - self.assertEqual(fontprops['slant'], 'italic') - self.assertEqual(fontprops['weight'], 'bold') - self.assertTrue(fontprops['underline']) - self.assertTrue(fontprops['overstrike']) - - def events(): - self.window.update() - c = list(self.window.children.values())[0] - c.bind('', test) - self.window.update() - c.withdraw() - self.window.update() - c.deiconify() - - self.window.after(100, events) - askfont(master=self.window, family='TkDefaultFont', size=20, - slant='italic', weight='bold', underline=True, overstrike=True) From 62c7b967e3d243c11945d7e1c16f58aaee25eff4 Mon Sep 17 00:00:00 2001 From: kurawlefaraaz <70267324+kurawlefaraaz@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:40:57 +0530 Subject: [PATCH 3/4] Add files via upload --- tk_simplefontchooser.py | 783 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 783 insertions(+) create mode 100644 tk_simplefontchooser.py diff --git a/tk_simplefontchooser.py b/tk_simplefontchooser.py new file mode 100644 index 0000000..bab5feb --- /dev/null +++ b/tk_simplefontchooser.py @@ -0,0 +1,783 @@ +from tkinter import Toplevel, StringVar, BooleanVar, IntVar +from tkinter.ttk import Checkbutton, Frame, Label, Button, Style, Spinbox, Combobox +from tkinter.font import Font, families, names + +from locale import getlocale + +__version__ = "2.0.3" # If this simple font chooser is also accepted + +# --- translation +EN = {"Cancel": "Cancel", "Bold": "Bold", "Italic": "Italic", + "Underline": "Underline", "Overstrike": "Strikethrough"} +FR = {"Cancel": "Annuler", "Bold": "Gras", "Italic": "Italique", + "Underline": "Souligné", "Overstrike": "Barré"} +IT = {"Cancel": "Annulla", "Bold": "Grassetto", "Italic": "Corsivo", + "Underline": "Sottolineato", "Overstrike": "Barrato"} +RU = {"Cancel": "Отмена", "Bold": "Полужирный", "Italic": "Курсив", + "Underline": "Подчеркнутый", "Overstrike": "Зачеркнутый"} +LANGUAGES = {"fr": FR, "en": EN, "it": IT, "ru": RU} + +try: + lang_code = getlocale()[0][:2] + if lang_code in LANGUAGES: + TR = LANGUAGES[lang_code] + else: + TR = LANGUAGES["en"] + +except ValueError: + TR = LANGUAGES["en"] + +class SimpleFontChooser(Toplevel): + + def __init__(self, master, font:Font = None, text="Abcd", title="Font Chooser", **options): + """ + Create a new FontChooser instance. + + Arguments: + + master : Tk or Toplevel instance + master window + + font : Font + ``Font`` object: + + text : str + text to be displayed in the preview label + + title : str + window title + + options : dict + additional keyword arguments to be passed to ``Toplevel.__init__`` + """ + Toplevel.__init__(self, master, **options) + self.title(title) + self.resizable(False, False) + self.protocol("WM_DELETE_WINDOW", self.destroy) + + # --- family list + self.font_list = list(set(families()).union(names())) + self.font_list.sort() + + if not font: self.font = Font(self, family="TkDefaultFont", size=10) + else: self.font = font + + ### Font Family Select + self.font_family_option_selected = StringVar(self, self.font.cget('family')) + family_menu = Combobox(self, textvariable=self.font_family_option_selected, values = self.font_list, height=10, state = 'readonly') + family_menu.bind("<>", self.update_family) + family_menu.grid(row=0, column=0, sticky="ew", pady=(10, 1), padx=(10, 0)) + + ### Font Size Select + self.font_size_selected = IntVar(self, self.font.cget('size')) + font_size_spinbox = Spinbox(self, from_=0, textvariable=self.font_size_selected, to='infinity', command=self.update_size, state="readonly") + + font_size_spinbox.grid(row=0, column=1, sticky="ew", + pady=(10, 1), padx=(10, 0)) + + ### Font Options + options_frame = Frame(self, relief='groove', borderwidth=2) + + self.var_bold = BooleanVar(self, self.font.cget('weight') == "bold") + b_bold = Checkbutton(options_frame, text=TR.get("Bold"), variable=self.var_bold, command=self.toggle_bold) + b_bold.grid(row=0, column=0, padx=5) + + self.var_italic = BooleanVar(self, self.font.cget('slant') == "italic") + b_italic = Checkbutton(options_frame, text=TR.get("Italic"), variable=self.var_italic, command=self.toggle_italic) + b_italic.grid(row=0, column=1, padx=5) + + self.var_underline = BooleanVar(self, self.font.cget('underline')) + b_underline = Checkbutton(options_frame, text=TR.get("Underline"), variable=self.var_underline, command=self.toggle_underline) + b_underline.grid(row=0, column=2, padx=5) + + self.var_overstrike = BooleanVar(self, self.font.cget('overstrike')) + b_overstrike = Checkbutton(options_frame, text=TR.get("Overstrike"), variable=self.var_overstrike, command=self.toggle_overstrike) + b_overstrike.grid(row=0, column=3, padx=5) + + options_frame.grid_columnconfigure(0, weight=1) + options_frame.grid_columnconfigure(1, weight=1) + options_frame.grid_columnconfigure(2, weight=1) + options_frame.grid_columnconfigure(3, weight=1) + options_frame.grid(row=1, column=0, columnspan=2, + padx=10, pady=10, ipadx=10, sticky="ew") + + ### Preview Label + style = Style(self) + style.configure("prev.TLabel", background="white") + + self.preview = Label(self, relief="groove", style="prev.TLabel", + text=text, font=self.font, + anchor="center") + self.preview.grid(row=2, column=0, columnspan=5, sticky="ew", + padx=10, pady=(0, 10), ipadx=4, ipady=4) + + ### Buttons + button_frame = Frame(self) + button_frame.grid(row=3, column=0, columnspan=2, pady=(0, 10), padx=10) + Button(button_frame, text="Ok", + command=self.ok_func).grid(row=0, column=0, padx=4, sticky='ew') + Button(button_frame, text="Cancel", + command=self.cancel_func).grid(row=0, column=1, padx=4, sticky='ew') + + def update_family(self, event): + self.font.configure(family=self.font_family_option_selected.get()) + + def update_size(self): + self.font.configure(size = self.font_size_selected.get()) + + def toggle_bold(self): + """Update font preview weight.""" + b = self.var_bold.get() + self.font.configure(weight=["normal", "bold"][b]) + + def toggle_italic(self): + """Update font font slant.""" + b = self.var_italic.get() + self.font.configure(slant=["roman", "italic"][b]) + + def toggle_underline(self): + """Update font preview underline.""" + b = self.var_underline.get() + self.font.configure(underline=b) + + def toggle_overstrike(self): + """Update font preview overstrike.""" + b = self.var_overstrike.get() + self.font.configure(overstrike=b) + + def cancel_func(self): + self.font = None + self.destroy() + + def ok_func(self): self.destroy() + + def get_result(self): + return self.font + +def askfont(master=None, text="Abcd", title="Font Chooser", font=None): + """ + Open the font chooser and return a dictionary of the font properties. + + General Arguments: + + master : Tk or Toplevel instance + master window + + text : str + sample text to be displayed in the font chooser + + title : str + dialog title + + Font arguments: + + family : str + font family + + size : int + font size + + slant : str + "roman" or "italic" + + weight : str + "normal" or "bold" + + underline : bool + whether the text is underlined + + overstrike : bool + whether the text is overstriked + + Output: Font Object + + """ + chooser = SimpleFontChooser(master, font, text, title) + chooser.wait_window(chooser) + return chooser.get_result() + + +if __name__ == "__main__": + """Example.""" + from tkinter import Tk + + + root = Tk() + style = Style(root) + bg = style.lookup("TLabel", "background") + root.configure(bg=bg) + label = Label(root, text='Chosen font: ') + label.pack(padx=10, pady=(10, 4)) + + def callback(): + font = askfont(root, title="Choose a font", text=label.cget('text')) + if font: + font_str = f"{font.cget('family')} {font.cget('size')} {font.cget('weight')} {font.cget('slant')}" + if font.cget('underline'): + font_str += ' underline' + if font.cget('overstrike'): + font_str += ' overstrike' + + label.configure(font=font, + text='Chosen font: ' + font_str) + + Button(root, text='Font Chooser', + command=callback).pack(padx=10, pady=(4, 10)) + root.mainloop() + +# -*- coding: utf-8 -*- +""" +tkFontChooser - Font chooser for Tkinter +Copyright 2016-2017 Juliette Monsel + +tkFontChooser is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +tkFontChooser is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +try: + from tkinter import Toplevel, Listbox, StringVar, BooleanVar, TclError + from tkinter.ttk import Checkbutton, Frame, Label, Button, Scrollbar, Style, Entry + from tkinter.font import families, Font +except ImportError: + from Tkinter import Toplevel, Listbox, StringVar, BooleanVar + from ttk import Checkbutton, Frame, Label, Button, Scrollbar, Style, Entry + from tkFont import families, Font + +from locale import getdefaultlocale + +__version__ = "2.0.2" + +# --- translation +EN = {"Cancel": "Cancel", "Bold": "Bold", "Italic": "Italic", + "Underline": "Underline", "Overstrike": "Strikethrough"} +FR = {"Cancel": "Annuler", "Bold": "Gras", "Italic": "Italique", + "Underline": "Souligné", "Overstrike": "Barré"} +IT = {"Cancel": "Annulla", "Bold": "Grassetto", "Italic": "Corsivo", + "Underline": "Sottolineato", "Overstrike": "Barrato"} +RU = {"Cancel": "Отмена", "Bold": "Полужирный", "Italic": "Курсив", + "Underline": "Подчеркнутый", "Overstrike": "Зачеркнутый"} +LANGUAGES = {"fr": FR, "en": EN, "it": IT, "ru": RU} + +try: + lang_code = getdefaultlocale()[0][:2] + if lang_code in LANGUAGES: + TR = LANGUAGES[lang_code] + else: + TR = LANGUAGES["en"] + +except ValueError: + TR = LANGUAGES["en"] + + +# --- FontChooser class +class FontChooser(Toplevel): + """Font chooser dialog.""" + + def __init__(self, master, font_dict={}, text="Abcd", title="Font Chooser", + **kwargs): + """ + Create a new FontChooser instance. + + Arguments: + + master : Tk or Toplevel instance + master window + + font_dict : dict + dictionnary, like the one returned by the ``actual`` method of a ``Font`` object: + + :: + + {'family': str, + 'size': int, + 'weight': 'bold'/'normal', + 'slant': 'italic'/'roman', + 'underline': bool, + 'overstrike': bool} + + text : str + text to be displayed in the preview label + + title : str + window title + + kwargs : dict + additional keyword arguments to be passed to ``Toplevel.__init__`` + """ + Toplevel.__init__(self, master, **kwargs) + self.title(title) + self.resizable(False, False) + self.protocol("WM_DELETE_WINDOW", self.quit) + self._validate_family = self.register(self.validate_font_family) + self._validate_size = self.register(self.validate_font_size) + + # --- variable storing the chosen font + self.res = "" + + style = Style(self) + style.configure("prev.TLabel", background="white") + bg = style.lookup("TLabel", "background") + self.configure(bg=bg) + + # --- family list + self.fonts = list(set(families())) + self.fonts.append("TkDefaultFont") + self.fonts.sort() + for i in range(len(self.fonts)): + self.fonts[i] = self.fonts[i].replace(" ", "\ ") + max_length = int(2.5 * max([len(font) for font in self.fonts])) // 3 + self.sizes = ["%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2)))] + # --- font default + font_dict["weight"] = font_dict.get("weight", "normal") + font_dict["slant"] = font_dict.get("slant", "roman") + font_dict["underline"] = font_dict.get("underline", False) + font_dict["overstrike"] = font_dict.get("overstrike", False) + font_dict["family"] = font_dict.get("family", + self.fonts[0].replace('\ ', ' ')) + font_dict["size"] = font_dict.get("size", 10) + + # --- creation of the widgets + # ------ style parameters (bold, italic ...) + options_frame = Frame(self, relief='groove', borderwidth=2) + self.font_family = StringVar(self, " ".join(self.fonts)) + self.font_size = StringVar(self, " ".join(self.sizes)) + self.var_bold = BooleanVar(self, font_dict["weight"] == "bold") + b_bold = Checkbutton(options_frame, text=TR["Bold"], + command=self.toggle_bold, + variable=self.var_bold) + b_bold.grid(row=0, sticky="w", padx=4, pady=(4, 2)) + self.var_italic = BooleanVar(self, font_dict["slant"] == "italic") + b_italic = Checkbutton(options_frame, text=TR["Italic"], + command=self.toggle_italic, + variable=self.var_italic) + b_italic.grid(row=1, sticky="w", padx=4, pady=2) + self.var_underline = BooleanVar(self, font_dict["underline"]) + b_underline = Checkbutton(options_frame, text=TR["Underline"], + command=self.toggle_underline, + variable=self.var_underline) + b_underline.grid(row=2, sticky="w", padx=4, pady=2) + self.var_overstrike = BooleanVar(self, font_dict["overstrike"]) + b_overstrike = Checkbutton(options_frame, text=TR["Overstrike"], + variable=self.var_overstrike, + command=self.toggle_overstrike) + b_overstrike.grid(row=3, sticky="w", padx=4, pady=(2, 4)) + # ------ Size and family + self.var_size = StringVar(self) + self.entry_family = Entry(self, width=max_length, validate="key", + validatecommand=(self._validate_family, "%d", "%S", + "%i", "%s", "%V")) + self.entry_size = Entry(self, width=4, validate="key", + textvariable=self.var_size, + validatecommand=(self._validate_size, "%d", "%P", "%V")) + self.list_family = Listbox(self, selectmode="browse", + listvariable=self.font_family, + highlightthickness=0, + exportselection=False, + width=max_length) + self.list_size = Listbox(self, selectmode="browse", + listvariable=self.font_size, + highlightthickness=0, + exportselection=False, + width=4) + scroll_family = Scrollbar(self, orient='vertical', + command=self.list_family.yview) + scroll_size = Scrollbar(self, orient='vertical', + command=self.list_size.yview) + self.preview_font = Font(self, **font_dict) + if len(text) > 30: + text = text[:30] + self.preview = Label(self, relief="groove", style="prev.TLabel", + text=text, font=self.preview_font, + anchor="center") + + # --- widget configuration + self.list_family.configure(yscrollcommand=scroll_family.set) + self.list_size.configure(yscrollcommand=scroll_size.set) + + self.entry_family.insert(0, font_dict["family"]) + self.entry_family.selection_clear() + self.entry_family.icursor("end") + self.entry_size.insert(0, font_dict["size"]) + + try: + i = self.fonts.index(self.entry_family.get().replace(" ", "\ ")) + except ValueError: + # unknown font + i = 0 + self.list_family.selection_clear(0, "end") + self.list_family.selection_set(i) + self.list_family.see(i) + try: + i = self.sizes.index(self.entry_size.get()) + self.list_size.selection_clear(0, "end") + self.list_size.selection_set(i) + self.list_size.see(i) + except ValueError: + # size not in list + pass + + self.entry_family.grid(row=0, column=0, sticky="ew", + pady=(10, 1), padx=(10, 0)) + self.entry_size.grid(row=0, column=2, sticky="ew", + pady=(10, 1), padx=(10, 0)) + self.list_family.grid(row=1, column=0, sticky="nsew", + pady=(1, 10), padx=(10, 0)) + self.list_size.grid(row=1, column=2, sticky="nsew", + pady=(1, 10), padx=(10, 0)) + scroll_family.grid(row=1, column=1, sticky='ns', pady=(1, 10)) + scroll_size.grid(row=1, column=3, sticky='ns', pady=(1, 10)) + options_frame.grid(row=0, column=4, rowspan=2, + padx=10, pady=10, ipadx=10) + + self.preview.grid(row=2, column=0, columnspan=5, sticky="eswn", + padx=10, pady=(0, 10), ipadx=4, ipady=4) + + button_frame = Frame(self) + button_frame.grid(row=3, column=0, columnspan=5, pady=(0, 10), padx=10) + + Button(button_frame, text="Ok", + command=self.ok).grid(row=0, column=0, padx=4, sticky='ew') + Button(button_frame, text=TR["Cancel"], + command=self.quit).grid(row=0, column=1, padx=4, sticky='ew') + self.list_family.bind('<>', self.update_entry_family) + self.list_size.bind('<>', self.update_entry_size, + add=True) + self.list_family.bind("", self.keypress) + self.entry_family.bind("", self.change_font_family) + self.entry_family.bind("", self.tab) + self.entry_size.bind("", self.change_font_size) + + self.entry_family.bind("", self.down_family) + self.entry_size.bind("", self.down_size) + + self.entry_family.bind("", self.up_family) + self.entry_size.bind("", self.up_size) + + # bind Ctrl+A to select all instead of go to beginning + self.bind_class("TEntry", "", self.select_all) + + self.wait_visibility(self) + self.grab_set() + self.entry_family.focus_set() + self.lift() + + def select_all(self, event): + """Select all entry content.""" + event.widget.selection_range(0, "end") + + def keypress(self, event): + """Select the first font whose name begin by the key pressed.""" + key = event.char.lower() + l = [i for i in self.fonts if i[0].lower() == key] + if l: + i = self.fonts.index(l[0]) + self.list_family.selection_clear(0, "end") + self.list_family.selection_set(i) + self.list_family.see(i) + self.update_entry_family() + + def up_family(self, event): + """Navigate in the family listbox with up key.""" + try: + i = self.list_family.curselection()[0] + self.list_family.selection_clear(0, "end") + if i <= 0: + i = len(self.fonts) + self.list_family.see(i - 1) + self.list_family.select_set(i - 1) + except TclError: + self.list_family.selection_clear(0, "end") + i = len(self.fonts) + self.list_family.see(i - 1) + self.list_family.select_set(i - 1) + self.list_family.event_generate('<>') + + def up_size(self, event): + """Navigate in the size listbox with up key.""" + try: + s = self.var_size.get() + if s in self.sizes: + i = self.sizes.index(s) + elif s: + sizes = list(self.sizes) + sizes.append(s) + sizes.sort(key=lambda x: int(x)) + i = sizes.index(s) + else: + i = 0 + self.list_size.selection_clear(0, "end") + if i <= 0: + i = len(self.sizes) + self.list_size.see(i - 1) + self.list_size.select_set(i - 1) + except TclError: + i = len(self.sizes) + self.list_size.see(i - 1) + self.list_size.select_set(i - 1) + self.list_size.event_generate('<>') + + def down_family(self, event): + """Navigate in the family listbox with down key.""" + try: + i = self.list_family.curselection()[0] + self.list_family.selection_clear(0, "end") + if i >= len(self.fonts): + i = -1 + self.list_family.see(i + 1) + self.list_family.select_set(i + 1) + except TclError: + self.list_family.selection_clear(0, "end") + self.list_family.see(0) + self.list_family.select_set(0) + self.list_family.event_generate('<>') + + def down_size(self, event): + """Navigate in the size listbox with down key.""" + try: + s = self.var_size.get() + if s in self.sizes: + i = self.sizes.index(s) + elif s: + sizes = list(self.sizes) + sizes.append(s) + sizes.sort(key=lambda x: int(x)) + i = sizes.index(s) - 1 + else: + s = len(self.sizes) - 1 + self.list_size.selection_clear(0, "end") + if i < len(self.sizes) - 1: + self.list_size.selection_set(i + 1) + self.list_size.see(i + 1) + else: + self.list_size.see(0) + self.list_size.select_set(0) + except TclError: + self.list_size.selection_set(0) + self.list_size.event_generate('<>') + + def toggle_bold(self): + """Update font preview weight.""" + b = self.var_bold.get() + self.preview_font.configure(weight=["normal", "bold"][b]) + + def toggle_italic(self): + """Update font preview slant.""" + b = self.var_italic.get() + self.preview_font.configure(slant=["roman", "italic"][b]) + + def toggle_underline(self): + """Update font preview underline.""" + b = self.var_underline.get() + self.preview_font.configure(underline=b) + + def toggle_overstrike(self): + """Update font preview overstrike.""" + b = self.var_overstrike.get() + self.preview_font.configure(overstrike=b) + + def change_font_family(self, event=None): + """Update font preview family.""" + family = self.entry_family.get() + if family.replace(" ", "\ ") in self.fonts: + self.preview_font.configure(family=family) + + def change_font_size(self, event=None): + """Update font preview size.""" + size = int(self.var_size.get()) + self.preview_font.configure(size=size) + + def validate_font_size(self, d, ch, V): + """Validation of the size entry content.""" + l = [i for i in self.sizes if i[:len(ch)] == ch] + i = None + if l: + i = self.sizes.index(l[0]) + elif ch.isdigit(): + sizes = list(self.sizes) + sizes.append(ch) + sizes.sort(key=lambda x: int(x)) + i = min(sizes.index(ch), len(self.sizes)) + if i is not None: + self.list_size.selection_clear(0, "end") + self.list_size.selection_set(i) + deb = self.list_size.nearest(0) + fin = self.list_size.nearest(self.list_size.winfo_height()) + if V != "forced": + if i < deb or i > fin: + self.list_size.see(i) + return True + if d == '1': + return ch.isdigit() + else: + return True + + def tab(self, event): + """Move at the end of selected text on tab press.""" + self.entry_family = event.widget + self.entry_family.selection_clear() + self.entry_family.icursor("end") + return "break" + + def validate_font_family(self, action, modif, pos, prev_txt, V): + """Completion of the text in the entry with existing font names.""" + if self.entry_family.selection_present(): + sel = self.entry_family.selection_get() + txt = prev_txt.replace(sel, '') + else: + txt = prev_txt + if action == "0": + txt = txt[:int(pos)] + txt[int(pos) + 1:] + return True + else: + txt = txt[:int(pos)] + modif + txt[int(pos):] + ch = txt.replace(" ", "\ ") + l = [i for i in self.fonts if i[:len(ch)] == ch] + if l: + i = self.fonts.index(l[0]) + self.list_family.selection_clear(0, "end") + self.list_family.selection_set(i) + deb = self.list_family.nearest(0) + fin = self.list_family.nearest(self.list_family.winfo_height()) + index = self.entry_family.index("insert") + self.entry_family.delete(0, "end") + self.entry_family.insert(0, l[0].replace("\ ", " ")) + self.entry_family.selection_range(index + 1, "end") + self.entry_family.icursor(index + 1) + if V != "forced": + if i < deb or i > fin: + self.list_family.see(i) + return True + else: + return False + + def update_entry_family(self, event=None): + """Update family entry when an item is selected in the family listbox.""" + # family = self.list_family.get("@%i,%i" % (event.x , event.y)) + family = self.list_family.get(self.list_family.curselection()[0]) + self.entry_family.delete(0, "end") + self.entry_family.insert(0, family) + self.entry_family.selection_clear() + self.entry_family.icursor("end") + self.change_font_family() + + def update_entry_size(self, event): + """Update size entry when an item is selected in the size listbox.""" + # size = self.list_size.get("@%i,%i" % (event.x , event.y)) + size = self.list_size.get(self.list_size.curselection()[0]) + self.var_size.set(size) + self.change_font_size() + + def ok(self): + """Validate choice.""" + self.res = self.preview_font.actual() + self.quit() + + def get_res(self): + """Return chosen font.""" + return self.res + + def quit(self): + self.destroy() + + +def askfont(master=None, text="Abcd", title="Font Chooser", **font_args): + """ + Open the font chooser and return a dictionary of the font properties. + + General Arguments: + + master : Tk or Toplevel instance + master window + + text : str + sample text to be displayed in the font chooser + + title : str + dialog title + + Font arguments: + + family : str + font family + + size : int + font size + + slant : str + "roman" or "italic" + + weight : str + "normal" or "bold" + + underline : bool + whether the text is underlined + + overstrike : bool + whether the text is overstriked + + Output: + + dictionary is similar to the one returned by the ``actual`` method of a tkinter ``Font`` object: + + :: + + {'family': str, + 'size': int, + 'weight': 'bold'/'normal', + 'slant': 'italic'/'roman', + 'underline': bool, + 'overstrike': bool} + + """ + chooser = FontChooser(master, font_args, text, title) + chooser.wait_window(chooser) + return chooser.get_res() + + +if __name__ == "__main__": + """Example.""" + try: + from tkinter import Tk + except ImportError: + from Tkinter import Tk + from sys import platform + + root = Tk() + style = Style(root) + if "win" == platform[:3]: + style.theme_use('vista') + elif "darwin" in platform: + style.theme_use('clam') + else: + style.theme_use('clam') + bg = style.lookup("TLabel", "background") + root.configure(bg=bg) + label = Label(root, text='Chosen font: ') + label.pack(padx=10, pady=(10, 4)) + + def callback(): + font = askfont(root, title="Choose a font") + if font: + # spaces in the family name need to be escaped + font['family'] = font['family'].replace(' ', '\ ') + font_str = "%(family)s %(size)i %(weight)s %(slant)s" % font + if font['underline']: + font_str += ' underline' + if font['overstrike']: + font_str += ' overstrike' + label.configure(font=font_str, + text='Chosen font: ' + font_str.replace('\ ', ' ')) + + Button(root, text='Font Chooser', + command=callback).pack(padx=10, pady=(4, 10)) + root.mainloop() \ No newline at end of file From 563a3ccffeae212b723b291a460f372e04c32c80 Mon Sep 17 00:00:00 2001 From: kurawlefaraaz <70267324+kurawlefaraaz@users.noreply.github.com> Date: Tue, 28 Jan 2025 19:56:17 +0530 Subject: [PATCH 4/4] Update tk_simplefontchooser.py Compatablity for Python2x --- tk_simplefontchooser.py | 568 +--------------------------------------- 1 file changed, 8 insertions(+), 560 deletions(-) diff --git a/tk_simplefontchooser.py b/tk_simplefontchooser.py index bab5feb..4de846d 100644 --- a/tk_simplefontchooser.py +++ b/tk_simplefontchooser.py @@ -1,6 +1,11 @@ -from tkinter import Toplevel, StringVar, BooleanVar, IntVar -from tkinter.ttk import Checkbutton, Frame, Label, Button, Style, Spinbox, Combobox -from tkinter.font import Font, families, names +try: + from tkinter import Toplevel, StringVar, BooleanVar, IntVar + from tkinter.ttk import Checkbutton, Frame, Label, Button, Style, Spinbox, Combobox + from tkinter.font import Font, families, names +except ImportError: + from Tkinter import Toplevel, StringVar, BooleanVar, IntVar + from ttk import Checkbutton, Frame, Label, Button, Style, Spinbox, Combobox + from tkFont import Font, families, names from locale import getlocale @@ -224,560 +229,3 @@ def callback(): Button(root, text='Font Chooser', command=callback).pack(padx=10, pady=(4, 10)) root.mainloop() - -# -*- coding: utf-8 -*- -""" -tkFontChooser - Font chooser for Tkinter -Copyright 2016-2017 Juliette Monsel - -tkFontChooser is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -tkFontChooser is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" - -try: - from tkinter import Toplevel, Listbox, StringVar, BooleanVar, TclError - from tkinter.ttk import Checkbutton, Frame, Label, Button, Scrollbar, Style, Entry - from tkinter.font import families, Font -except ImportError: - from Tkinter import Toplevel, Listbox, StringVar, BooleanVar - from ttk import Checkbutton, Frame, Label, Button, Scrollbar, Style, Entry - from tkFont import families, Font - -from locale import getdefaultlocale - -__version__ = "2.0.2" - -# --- translation -EN = {"Cancel": "Cancel", "Bold": "Bold", "Italic": "Italic", - "Underline": "Underline", "Overstrike": "Strikethrough"} -FR = {"Cancel": "Annuler", "Bold": "Gras", "Italic": "Italique", - "Underline": "Souligné", "Overstrike": "Barré"} -IT = {"Cancel": "Annulla", "Bold": "Grassetto", "Italic": "Corsivo", - "Underline": "Sottolineato", "Overstrike": "Barrato"} -RU = {"Cancel": "Отмена", "Bold": "Полужирный", "Italic": "Курсив", - "Underline": "Подчеркнутый", "Overstrike": "Зачеркнутый"} -LANGUAGES = {"fr": FR, "en": EN, "it": IT, "ru": RU} - -try: - lang_code = getdefaultlocale()[0][:2] - if lang_code in LANGUAGES: - TR = LANGUAGES[lang_code] - else: - TR = LANGUAGES["en"] - -except ValueError: - TR = LANGUAGES["en"] - - -# --- FontChooser class -class FontChooser(Toplevel): - """Font chooser dialog.""" - - def __init__(self, master, font_dict={}, text="Abcd", title="Font Chooser", - **kwargs): - """ - Create a new FontChooser instance. - - Arguments: - - master : Tk or Toplevel instance - master window - - font_dict : dict - dictionnary, like the one returned by the ``actual`` method of a ``Font`` object: - - :: - - {'family': str, - 'size': int, - 'weight': 'bold'/'normal', - 'slant': 'italic'/'roman', - 'underline': bool, - 'overstrike': bool} - - text : str - text to be displayed in the preview label - - title : str - window title - - kwargs : dict - additional keyword arguments to be passed to ``Toplevel.__init__`` - """ - Toplevel.__init__(self, master, **kwargs) - self.title(title) - self.resizable(False, False) - self.protocol("WM_DELETE_WINDOW", self.quit) - self._validate_family = self.register(self.validate_font_family) - self._validate_size = self.register(self.validate_font_size) - - # --- variable storing the chosen font - self.res = "" - - style = Style(self) - style.configure("prev.TLabel", background="white") - bg = style.lookup("TLabel", "background") - self.configure(bg=bg) - - # --- family list - self.fonts = list(set(families())) - self.fonts.append("TkDefaultFont") - self.fonts.sort() - for i in range(len(self.fonts)): - self.fonts[i] = self.fonts[i].replace(" ", "\ ") - max_length = int(2.5 * max([len(font) for font in self.fonts])) // 3 - self.sizes = ["%i" % i for i in (list(range(6, 17)) + list(range(18, 32, 2)))] - # --- font default - font_dict["weight"] = font_dict.get("weight", "normal") - font_dict["slant"] = font_dict.get("slant", "roman") - font_dict["underline"] = font_dict.get("underline", False) - font_dict["overstrike"] = font_dict.get("overstrike", False) - font_dict["family"] = font_dict.get("family", - self.fonts[0].replace('\ ', ' ')) - font_dict["size"] = font_dict.get("size", 10) - - # --- creation of the widgets - # ------ style parameters (bold, italic ...) - options_frame = Frame(self, relief='groove', borderwidth=2) - self.font_family = StringVar(self, " ".join(self.fonts)) - self.font_size = StringVar(self, " ".join(self.sizes)) - self.var_bold = BooleanVar(self, font_dict["weight"] == "bold") - b_bold = Checkbutton(options_frame, text=TR["Bold"], - command=self.toggle_bold, - variable=self.var_bold) - b_bold.grid(row=0, sticky="w", padx=4, pady=(4, 2)) - self.var_italic = BooleanVar(self, font_dict["slant"] == "italic") - b_italic = Checkbutton(options_frame, text=TR["Italic"], - command=self.toggle_italic, - variable=self.var_italic) - b_italic.grid(row=1, sticky="w", padx=4, pady=2) - self.var_underline = BooleanVar(self, font_dict["underline"]) - b_underline = Checkbutton(options_frame, text=TR["Underline"], - command=self.toggle_underline, - variable=self.var_underline) - b_underline.grid(row=2, sticky="w", padx=4, pady=2) - self.var_overstrike = BooleanVar(self, font_dict["overstrike"]) - b_overstrike = Checkbutton(options_frame, text=TR["Overstrike"], - variable=self.var_overstrike, - command=self.toggle_overstrike) - b_overstrike.grid(row=3, sticky="w", padx=4, pady=(2, 4)) - # ------ Size and family - self.var_size = StringVar(self) - self.entry_family = Entry(self, width=max_length, validate="key", - validatecommand=(self._validate_family, "%d", "%S", - "%i", "%s", "%V")) - self.entry_size = Entry(self, width=4, validate="key", - textvariable=self.var_size, - validatecommand=(self._validate_size, "%d", "%P", "%V")) - self.list_family = Listbox(self, selectmode="browse", - listvariable=self.font_family, - highlightthickness=0, - exportselection=False, - width=max_length) - self.list_size = Listbox(self, selectmode="browse", - listvariable=self.font_size, - highlightthickness=0, - exportselection=False, - width=4) - scroll_family = Scrollbar(self, orient='vertical', - command=self.list_family.yview) - scroll_size = Scrollbar(self, orient='vertical', - command=self.list_size.yview) - self.preview_font = Font(self, **font_dict) - if len(text) > 30: - text = text[:30] - self.preview = Label(self, relief="groove", style="prev.TLabel", - text=text, font=self.preview_font, - anchor="center") - - # --- widget configuration - self.list_family.configure(yscrollcommand=scroll_family.set) - self.list_size.configure(yscrollcommand=scroll_size.set) - - self.entry_family.insert(0, font_dict["family"]) - self.entry_family.selection_clear() - self.entry_family.icursor("end") - self.entry_size.insert(0, font_dict["size"]) - - try: - i = self.fonts.index(self.entry_family.get().replace(" ", "\ ")) - except ValueError: - # unknown font - i = 0 - self.list_family.selection_clear(0, "end") - self.list_family.selection_set(i) - self.list_family.see(i) - try: - i = self.sizes.index(self.entry_size.get()) - self.list_size.selection_clear(0, "end") - self.list_size.selection_set(i) - self.list_size.see(i) - except ValueError: - # size not in list - pass - - self.entry_family.grid(row=0, column=0, sticky="ew", - pady=(10, 1), padx=(10, 0)) - self.entry_size.grid(row=0, column=2, sticky="ew", - pady=(10, 1), padx=(10, 0)) - self.list_family.grid(row=1, column=0, sticky="nsew", - pady=(1, 10), padx=(10, 0)) - self.list_size.grid(row=1, column=2, sticky="nsew", - pady=(1, 10), padx=(10, 0)) - scroll_family.grid(row=1, column=1, sticky='ns', pady=(1, 10)) - scroll_size.grid(row=1, column=3, sticky='ns', pady=(1, 10)) - options_frame.grid(row=0, column=4, rowspan=2, - padx=10, pady=10, ipadx=10) - - self.preview.grid(row=2, column=0, columnspan=5, sticky="eswn", - padx=10, pady=(0, 10), ipadx=4, ipady=4) - - button_frame = Frame(self) - button_frame.grid(row=3, column=0, columnspan=5, pady=(0, 10), padx=10) - - Button(button_frame, text="Ok", - command=self.ok).grid(row=0, column=0, padx=4, sticky='ew') - Button(button_frame, text=TR["Cancel"], - command=self.quit).grid(row=0, column=1, padx=4, sticky='ew') - self.list_family.bind('<>', self.update_entry_family) - self.list_size.bind('<>', self.update_entry_size, - add=True) - self.list_family.bind("", self.keypress) - self.entry_family.bind("", self.change_font_family) - self.entry_family.bind("", self.tab) - self.entry_size.bind("", self.change_font_size) - - self.entry_family.bind("", self.down_family) - self.entry_size.bind("", self.down_size) - - self.entry_family.bind("", self.up_family) - self.entry_size.bind("", self.up_size) - - # bind Ctrl+A to select all instead of go to beginning - self.bind_class("TEntry", "", self.select_all) - - self.wait_visibility(self) - self.grab_set() - self.entry_family.focus_set() - self.lift() - - def select_all(self, event): - """Select all entry content.""" - event.widget.selection_range(0, "end") - - def keypress(self, event): - """Select the first font whose name begin by the key pressed.""" - key = event.char.lower() - l = [i for i in self.fonts if i[0].lower() == key] - if l: - i = self.fonts.index(l[0]) - self.list_family.selection_clear(0, "end") - self.list_family.selection_set(i) - self.list_family.see(i) - self.update_entry_family() - - def up_family(self, event): - """Navigate in the family listbox with up key.""" - try: - i = self.list_family.curselection()[0] - self.list_family.selection_clear(0, "end") - if i <= 0: - i = len(self.fonts) - self.list_family.see(i - 1) - self.list_family.select_set(i - 1) - except TclError: - self.list_family.selection_clear(0, "end") - i = len(self.fonts) - self.list_family.see(i - 1) - self.list_family.select_set(i - 1) - self.list_family.event_generate('<>') - - def up_size(self, event): - """Navigate in the size listbox with up key.""" - try: - s = self.var_size.get() - if s in self.sizes: - i = self.sizes.index(s) - elif s: - sizes = list(self.sizes) - sizes.append(s) - sizes.sort(key=lambda x: int(x)) - i = sizes.index(s) - else: - i = 0 - self.list_size.selection_clear(0, "end") - if i <= 0: - i = len(self.sizes) - self.list_size.see(i - 1) - self.list_size.select_set(i - 1) - except TclError: - i = len(self.sizes) - self.list_size.see(i - 1) - self.list_size.select_set(i - 1) - self.list_size.event_generate('<>') - - def down_family(self, event): - """Navigate in the family listbox with down key.""" - try: - i = self.list_family.curselection()[0] - self.list_family.selection_clear(0, "end") - if i >= len(self.fonts): - i = -1 - self.list_family.see(i + 1) - self.list_family.select_set(i + 1) - except TclError: - self.list_family.selection_clear(0, "end") - self.list_family.see(0) - self.list_family.select_set(0) - self.list_family.event_generate('<>') - - def down_size(self, event): - """Navigate in the size listbox with down key.""" - try: - s = self.var_size.get() - if s in self.sizes: - i = self.sizes.index(s) - elif s: - sizes = list(self.sizes) - sizes.append(s) - sizes.sort(key=lambda x: int(x)) - i = sizes.index(s) - 1 - else: - s = len(self.sizes) - 1 - self.list_size.selection_clear(0, "end") - if i < len(self.sizes) - 1: - self.list_size.selection_set(i + 1) - self.list_size.see(i + 1) - else: - self.list_size.see(0) - self.list_size.select_set(0) - except TclError: - self.list_size.selection_set(0) - self.list_size.event_generate('<>') - - def toggle_bold(self): - """Update font preview weight.""" - b = self.var_bold.get() - self.preview_font.configure(weight=["normal", "bold"][b]) - - def toggle_italic(self): - """Update font preview slant.""" - b = self.var_italic.get() - self.preview_font.configure(slant=["roman", "italic"][b]) - - def toggle_underline(self): - """Update font preview underline.""" - b = self.var_underline.get() - self.preview_font.configure(underline=b) - - def toggle_overstrike(self): - """Update font preview overstrike.""" - b = self.var_overstrike.get() - self.preview_font.configure(overstrike=b) - - def change_font_family(self, event=None): - """Update font preview family.""" - family = self.entry_family.get() - if family.replace(" ", "\ ") in self.fonts: - self.preview_font.configure(family=family) - - def change_font_size(self, event=None): - """Update font preview size.""" - size = int(self.var_size.get()) - self.preview_font.configure(size=size) - - def validate_font_size(self, d, ch, V): - """Validation of the size entry content.""" - l = [i for i in self.sizes if i[:len(ch)] == ch] - i = None - if l: - i = self.sizes.index(l[0]) - elif ch.isdigit(): - sizes = list(self.sizes) - sizes.append(ch) - sizes.sort(key=lambda x: int(x)) - i = min(sizes.index(ch), len(self.sizes)) - if i is not None: - self.list_size.selection_clear(0, "end") - self.list_size.selection_set(i) - deb = self.list_size.nearest(0) - fin = self.list_size.nearest(self.list_size.winfo_height()) - if V != "forced": - if i < deb or i > fin: - self.list_size.see(i) - return True - if d == '1': - return ch.isdigit() - else: - return True - - def tab(self, event): - """Move at the end of selected text on tab press.""" - self.entry_family = event.widget - self.entry_family.selection_clear() - self.entry_family.icursor("end") - return "break" - - def validate_font_family(self, action, modif, pos, prev_txt, V): - """Completion of the text in the entry with existing font names.""" - if self.entry_family.selection_present(): - sel = self.entry_family.selection_get() - txt = prev_txt.replace(sel, '') - else: - txt = prev_txt - if action == "0": - txt = txt[:int(pos)] + txt[int(pos) + 1:] - return True - else: - txt = txt[:int(pos)] + modif + txt[int(pos):] - ch = txt.replace(" ", "\ ") - l = [i for i in self.fonts if i[:len(ch)] == ch] - if l: - i = self.fonts.index(l[0]) - self.list_family.selection_clear(0, "end") - self.list_family.selection_set(i) - deb = self.list_family.nearest(0) - fin = self.list_family.nearest(self.list_family.winfo_height()) - index = self.entry_family.index("insert") - self.entry_family.delete(0, "end") - self.entry_family.insert(0, l[0].replace("\ ", " ")) - self.entry_family.selection_range(index + 1, "end") - self.entry_family.icursor(index + 1) - if V != "forced": - if i < deb or i > fin: - self.list_family.see(i) - return True - else: - return False - - def update_entry_family(self, event=None): - """Update family entry when an item is selected in the family listbox.""" - # family = self.list_family.get("@%i,%i" % (event.x , event.y)) - family = self.list_family.get(self.list_family.curselection()[0]) - self.entry_family.delete(0, "end") - self.entry_family.insert(0, family) - self.entry_family.selection_clear() - self.entry_family.icursor("end") - self.change_font_family() - - def update_entry_size(self, event): - """Update size entry when an item is selected in the size listbox.""" - # size = self.list_size.get("@%i,%i" % (event.x , event.y)) - size = self.list_size.get(self.list_size.curselection()[0]) - self.var_size.set(size) - self.change_font_size() - - def ok(self): - """Validate choice.""" - self.res = self.preview_font.actual() - self.quit() - - def get_res(self): - """Return chosen font.""" - return self.res - - def quit(self): - self.destroy() - - -def askfont(master=None, text="Abcd", title="Font Chooser", **font_args): - """ - Open the font chooser and return a dictionary of the font properties. - - General Arguments: - - master : Tk or Toplevel instance - master window - - text : str - sample text to be displayed in the font chooser - - title : str - dialog title - - Font arguments: - - family : str - font family - - size : int - font size - - slant : str - "roman" or "italic" - - weight : str - "normal" or "bold" - - underline : bool - whether the text is underlined - - overstrike : bool - whether the text is overstriked - - Output: - - dictionary is similar to the one returned by the ``actual`` method of a tkinter ``Font`` object: - - :: - - {'family': str, - 'size': int, - 'weight': 'bold'/'normal', - 'slant': 'italic'/'roman', - 'underline': bool, - 'overstrike': bool} - - """ - chooser = FontChooser(master, font_args, text, title) - chooser.wait_window(chooser) - return chooser.get_res() - - -if __name__ == "__main__": - """Example.""" - try: - from tkinter import Tk - except ImportError: - from Tkinter import Tk - from sys import platform - - root = Tk() - style = Style(root) - if "win" == platform[:3]: - style.theme_use('vista') - elif "darwin" in platform: - style.theme_use('clam') - else: - style.theme_use('clam') - bg = style.lookup("TLabel", "background") - root.configure(bg=bg) - label = Label(root, text='Chosen font: ') - label.pack(padx=10, pady=(10, 4)) - - def callback(): - font = askfont(root, title="Choose a font") - if font: - # spaces in the family name need to be escaped - font['family'] = font['family'].replace(' ', '\ ') - font_str = "%(family)s %(size)i %(weight)s %(slant)s" % font - if font['underline']: - font_str += ' underline' - if font['overstrike']: - font_str += ' overstrike' - label.configure(font=font_str, - text='Chosen font: ' + font_str.replace('\ ', ' ')) - - Button(root, text='Font Chooser', - command=callback).pack(padx=10, pady=(4, 10)) - root.mainloop() \ No newline at end of file