def GetFont(self, root, configType, section): """Retrieve a font from configuration (font, font-size, font-bold) Intercept the special value 'TkFixedFont' and substitute the actual font, factoring in some tweaks if needed for appearance sakes. The 'root' parameter can normally be any valid Tkinter widget. Return a tuple (family, size, weight) suitable for passing to tkinter.Font """ family = self.GetOption(configType, section, 'font', default='courier') size = self.GetOption(configType, section, 'font-size', type='int', default='10') bold = self.GetOption(configType, section, 'font-bold', default=0, type='bool') if (family == 'TkFixedFont'): f = Font(name='TkFixedFont', exists=True, root=root) actualFont = Font.actual(f) family = actualFont['family'] size = actualFont['size'] if size <= 0: size = 10 # if font in pixels, ignore actual size bold = actualFont['weight'] == 'bold' return (family, size, 'bold' if bold else 'normal')
def GetFont(self, root, configType, section): """Retrieve a font from configuration (font, font-size, font-bold) Intercept the special value 'TkFixedFont' and substitute the actual font, factoring in some tweaks if needed for appearance sakes. The 'root' parameter can normally be any valid Tkinter widget. Return a tuple (family, size, weight) suitable for passing to tkinter.Font """ family = self.GetOption(configType, section, "font", default="courier") size = self.GetOption(configType, section, "font-size", type="int", default="10") bold = self.GetOption(configType, section, "font-bold", default=0, type="bool") if family == "TkFixedFont": if TkVersion < 8.5: family = "Courier" else: f = Font(name="TkFixedFont", exists=True, root=root) actualFont = Font.actual(f) family = actualFont["family"] size = actualFont["size"] if size < 0: size = 10 # if font in pixels, ignore actual size bold = actualFont["weight"] == "bold" return (family, size, "bold" if bold else "normal")
def configure(self, **kwargs): if 'text' in kwargs: self.label.configure(text=kwargs.pop('text')) if 'image' in kwargs: self.label.configure(image=kwargs.pop('image')) if 'background' in kwargs: self.style.configure('tooltip.TLabel', background=kwargs['background']) if 'foreground' in kwargs: fg = kwargs.pop('foreground') self.style.configure('tooltip.TLabel', foreground=fg) if 'alpha' in kwargs: self.attributes('-alpha', kwargs.pop('alpha')) if 'font' in kwargs: font = Font(self, kwargs.pop('font')) self.font.configure(**font.actual()) Toplevel.configure(self, **kwargs)
def test_get_font(self): from test.support import requires from tkinter import Tk from tkinter.font import Font conf = self.mock_config() requires('gui') root = Tk() root.withdraw() f = Font.actual(Font(name='TkFixedFont', exists=True, root=root)) self.assertEqual( conf.GetFont(root, 'main', 'EditorWindow'), (f['family'], 10 if f['size'] <= 0 else f['size'], f['weight'])) # Cleanup root root.destroy() del root
class Calendar(ttk.Frame): """Calendar widget.""" date = calendar.datetime.date timedelta = calendar.datetime.timedelta strptime = calendar.datetime.datetime.strptime strftime = calendar.datetime.datetime.strftime def __init__(self, master=None, **kw): """ Construct a Calendar with parent master. STANDARD OPTIONS cursor, font, borderwidth, state WIDGET-SPECIFIC OPTIONS year, month: initially displayed month, default is current month day: initially selected day, if month or year is given but not day, no initial selection, otherwise, default is today locale: locale to use, e.g. 'fr_FR' selectmode: "none" or "day" (default) define whether the user can change the selected day with a mouse click showweeknumbers: boolean (default is True) to show/hide week numbers textvariable: StringVar that will contain the currently selected date as str background: background color of calendar border and month/year name foreground: foreground color of month/year name bordercolor: day border color selectbackground: background color of selected day selectforeground: foreground color of selected day disabledselectbackground: background color of selected day in disabled state disabledselectforeground: foreground color of selected day in disabled state normalbackground: background color of normal week days normalforeground: foreground color of normal week days othermonthforeground: foreground color of normal week days belonging to the previous/next month othermonthbackground: background color of normal week days belonging to the previous/next month othermonthweforeground: foreground color of week-end days belonging to the previous/next month othermonthwebackground: background color of week-end days belonging to the previous/next month weekendbackground: background color of week-end days weekendforeground: foreground color of week-end days headersbackground: background color of day names and week numbers headersforeground: foreground color of day names and week numbers disableddaybackground: background color of days in disabled state disableddayforeground: foreground color of days in disabled state VIRTUAL EVENTS A <<CalendarSelected>> event is generated each time the user selects a day with the mouse. """ curs = kw.pop("cursor", "") font = kw.pop("font", "Liberation\ Sans 9") classname = kw.pop('class_', "Calendar") name = kw.pop('name', None) ttk.Frame.__init__(self, master, class_=classname, cursor=curs, name=name) self._style_prefixe = str(self) ttk.Frame.configure(self, style='main.%s.TFrame' % self._style_prefixe) self._textvariable = kw.pop("textvariable", None) self._font = Font(self, font) prop = self._font.actual() prop["size"] += 1 self._header_font = Font(self, **prop) # state state = kw.get('state', 'normal') try: bd = int(kw.pop('borderwidth', 2)) except ValueError: raise ValueError('expected integer for the borderwidth option.') self._cal = calendar.TextCalendar(calendar.MONDAY) # --- locale locale = kw.pop("locale", getdefaultlocale()[0]) self._day_names = get_day_names('abbreviated', locale=locale) self._month_names = get_month_names('wide', locale=locale) # --- date today = self.date.today() if (("month" in kw) or ("year" in kw)) and ("day" not in kw): month = kw.pop("month", today.month) year = kw.pop('year', today.year) self._sel_date = None # selected day else: day = kw.pop('day', today.day) month = kw.pop("month", today.month) year = kw.pop('year', today.year) try: self._sel_date = self.date(year, month, day) # selected day if self._textvariable is not None: self._textvariable.set(format_date(self._sel_date, 'short', locale)) except ValueError: self._sel_date = None self._date = self.date(year, month, 1) # (year, month) displayed by the calendar # --- selectmode selectmode = kw.pop("selectmode", "day") if selectmode not in ("none", "day"): raise ValueError("'selectmode' option should be 'none' or 'day'.") # --- show week numbers showweeknumbers = kw.pop('showweeknumbers', True) # --- style self.style = ttk.Style(self) active_bg = self.style.lookup('TEntry', 'selectbackground', ('focus',)) dis_active_bg = self.style.lookup('TEntry', 'selectbackground', ('disabled',)) dis_bg = self.style.lookup('TLabel', 'background', ('disabled',)) dis_fg = self.style.lookup('TLabel', 'foreground', ('disabled',)) # --- properties options = ['cursor', 'font', 'borderwidth', 'state', 'selectmode', 'textvariable', 'locale', 'showweeknumbers', 'selectbackground', 'selectforeground', 'disabledselectbackground', 'disabledselectforeground', 'normalbackground', 'normalforeground', 'background', 'foreground', 'bordercolor', 'othermonthforeground', 'othermonthbackground', 'othermonthweforeground', 'othermonthwebackground', 'weekendbackground', 'weekendforeground', 'headersbackground', 'headersforeground', 'disableddaybackground', 'disableddayforeground'] keys = list(kw.keys()) for option in keys: if option not in options: del(kw[option]) self._properties = {"cursor": curs, "font": font, "borderwidth": bd, "state": state, "locale": locale, "selectmode": selectmode, 'textvariable': self._textvariable, 'showweeknumbers': showweeknumbers, 'selectbackground': active_bg, 'selectforeground': 'white', 'disabledselectbackground': dis_active_bg, 'disabledselectforeground': 'white', 'normalbackground': 'white', 'normalforeground': 'black', 'background': 'gray30', 'foreground': 'white', 'bordercolor': 'gray70', 'othermonthforeground': 'gray45', 'othermonthbackground': 'gray93', 'othermonthweforeground': 'gray45', 'othermonthwebackground': 'gray75', 'weekendbackground': 'gray80', 'weekendforeground': 'gray30', 'headersbackground': 'gray70', 'headersforeground': 'black', 'disableddaybackground': dis_bg, 'disableddayforeground': dis_fg} self._properties.update(kw) # --- init calendar # --- *-- header: month - year header = ttk.Frame(self, style='main.%s.TFrame' % self._style_prefixe) f_month = ttk.Frame(header, style='main.%s.TFrame' % self._style_prefixe) self._l_month = ttk.Button(f_month, style='L.%s.TButton' % self._style_prefixe, command=self._prev_month) self._header_month = ttk.Label(f_month, width=10, anchor='center', style='main.%s.TLabel' % self._style_prefixe, font=self._header_font) self._r_month = ttk.Button(f_month, style='R.%s.TButton' % self._style_prefixe, command=self._next_month) self._l_month.pack(side='left', fill="y") self._header_month.pack(side='left', padx=4) self._r_month.pack(side='left', fill="y") f_year = ttk.Frame(header, style='main.%s.TFrame' % self._style_prefixe) self._l_year = ttk.Button(f_year, style='L.%s.TButton' % self._style_prefixe, command=self._prev_year) self._header_year = ttk.Label(f_year, width=4, anchor='center', style='main.%s.TLabel' % self._style_prefixe, font=self._header_font) self._r_year = ttk.Button(f_year, style='R.%s.TButton' % self._style_prefixe, command=self._next_year) self._l_year.pack(side='left', fill="y") self._header_year.pack(side='left', padx=4) self._r_year.pack(side='left', fill="y") f_month.pack(side='left', fill='x') f_year.pack(side='right') # --- *-- calendar self._cal_frame = ttk.Frame(self, style='cal.%s.TFrame' % self._style_prefixe) ttk.Label(self._cal_frame, style='headers.%s.TLabel' % self._style_prefixe).grid(row=0, column=0, sticky="eswn") for i in range(7): d = self._day_names[i] self._cal_frame.columnconfigure(i + 1, weight=1) ttk.Label(self._cal_frame, font=self._font, style='headers.%s.TLabel' % self._style_prefixe, anchor="center", text=d, width=4).grid(row=0, column=i + 1, sticky="ew", pady=(0, 1)) self._week_nbs = [] self._calendar = [] for i in range(1, 7): self._cal_frame.rowconfigure(i, weight=1) wlabel = ttk.Label(self._cal_frame, style='headers.%s.TLabel' % self._style_prefixe, font=self._font, padding=2, anchor="e", width=2) self._week_nbs.append(wlabel) wlabel.grid(row=i, column=0, sticky="esnw", padx=(0, 1)) if not showweeknumbers: wlabel.grid_remove() self._calendar.append([]) for j in range(1, 8): label = ttk.Label(self._cal_frame, style='normal.%s.TLabel' % self._style_prefixe, font=self._font, anchor="center") self._calendar[-1].append(label) label.grid(row=i, column=j, padx=(0, 1), pady=(0, 1), sticky="nsew") if selectmode is "day": label.bind("<1>", self._on_click) # --- *-- pack main elements header.pack(fill="x", padx=2, pady=2) self._cal_frame.pack(fill="both", expand=True, padx=bd, pady=bd) self.config(state=state) # --- bindings self.bind('<<ThemeChanged>>', self._setup_style) self._setup_style() self._display_calendar() if self._textvariable is not None: try: self._textvariable_trace_id = self._textvariable.trace_add('write', self._textvariable_trace) except AttributeError: self._textvariable_trace_id = self._textvariable.trace('w', self._textvariable_trace) def __getitem__(self, key): """Return the resource value for a KEY given as string.""" try: return self._properties[key] except KeyError: raise AttributeError("Calendar object has no attribute %s." % key) def __setitem__(self, key, value): if key not in self._properties: raise AttributeError("Calendar object has no attribute %s." % key) elif key is "locale": raise AttributeError("This attribute cannot be modified.") else: if key is "selectmode": if value is "none": for week in self._calendar: for day in week: day.unbind("<1>") elif value is "day": for week in self._calendar: for day in week: day.bind("<1>", self._on_click) else: raise ValueError("'selectmode' option should be 'none' or 'day'.") elif key is 'textvariable': if self._sel_date is not None: if value is not None: value.set(self.format_date(self._sel_date)) try: if self._textvariable is not None: self._textvariable.trace_remove('write', self._textvariable_trace_id) if value is not None: self._textvariable_trace_id = value.trace_add('write', self._textvariable_trace) except AttributeError: if self._textvariable is not None: self._textvariable.trace_vdelete('w', self._textvariable_trace_id) if value is not None: value.trace('w', self._textvariable_trace) self._textvariable = value elif key is 'showweeknumbers': if value: for wlabel in self._week_nbs: wlabel.grid() else: for wlabel in self._week_nbs: wlabel.grid_remove() elif key is 'borderwidth': try: bd = int(value) self._cal_frame.pack_configure(padx=bd, pady=bd) except ValueError: raise ValueError('expected integer for the borderwidth option.') elif key is 'state': if value not in ['normal', 'disabled']: raise ValueError("bad state '%s': must be disabled or normal" % value) else: state = '!' * (value == 'normal') + 'disabled' self._l_year.state((state,)) self._r_year.state((state,)) self._l_month.state((state,)) self._r_month.state((state,)) for child in self._cal_frame.children.values(): child.state((state,)) elif key is "font": font = Font(self, value) prop = font.actual() self._font.configure(**prop) prop["size"] += 1 self._header_font.configure(**prop) size = max(prop["size"], 10) self.style.configure('R.%s.TButton' % self._style_prefixe, arrowsize=size) self.style.configure('L.%s.TButton' % self._style_prefixe, arrowsize=size) elif key is "normalbackground": self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value) self.style.configure('normal.%s.TLabel' % self._style_prefixe, background=value) self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "normalforeground": self.style.configure('normal.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "bordercolor": self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value) elif key is "othermonthforeground": self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "othermonthbackground": self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "othermonthweforeground": self.style.configure('we_om.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "othermonthwebackground": self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "selectbackground": self.style.configure('sel.%s.TLabel' % self._style_prefixe, background=value) elif key is "selectforeground": self.style.configure('sel.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "disabledselectbackground": self.style.map('sel.%s.TLabel' % self._style_prefixe, background=[('disabled', value)]) elif key is "disabledselectforeground": self.style.map('sel.%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)]) elif key is "disableddaybackground": self.style.map('%s.TLabel' % self._style_prefixe, background=[('disabled', value)]) elif key is "disableddayforeground": self.style.map('%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)]) elif key is "weekendbackground": self.style.configure('we.%s.TLabel' % self._style_prefixe, background=value) self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "weekendforeground": self.style.configure('we.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "headersbackground": self.style.configure('headers.%s.TLabel' % self._style_prefixe, background=value) elif key is "headersforeground": self.style.configure('headers.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "background": self.style.configure('main.%s.TFrame' % self._style_prefixe, background=value) self.style.configure('main.%s.TLabel' % self._style_prefixe, background=value) self.style.configure('R.%s.TButton' % self._style_prefixe, background=value, bordercolor=value, lightcolor=value, darkcolor=value) self.style.configure('L.%s.TButton' % self._style_prefixe, background=value, bordercolor=value, lightcolor=value, darkcolor=value) elif key is "foreground": self.style.configure('R.%s.TButton' % self._style_prefixe, arrowcolor=value) self.style.configure('L.%s.TButton' % self._style_prefixe, arrowcolor=value) self.style.configure('main.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "cursor": ttk.Frame.configure(self, cursor=value) self._properties[key] = value def _textvariable_trace(self, *args): if self._properties.get("selectmode") is "day": date = self._textvariable.get() if not date: self._remove_selection() self._sel_date = None else: try: self._sel_date = self.parse_date(date) except Exception: if self._sel_date is None: self._textvariable.set('') else: self._textvariable.set(self.format_date(self._sel_date)) raise ValueError("%r is not a valid date." % date) else: self._date = self._sel_date.replace(day=1) self._display_calendar() self._display_selection() def _setup_style(self, event=None): """Configure style.""" self.style.layout('L.%s.TButton' % self._style_prefixe, [('Button.focus', {'children': [('Button.leftarrow', None)]})]) self.style.layout('R.%s.TButton' % self._style_prefixe, [('Button.focus', {'children': [('Button.rightarrow', None)]})]) active_bg = self.style.lookup('TEntry', 'selectbackground', ('focus',)) sel_bg = self._properties.get('selectbackground') sel_fg = self._properties.get('selectforeground') dis_sel_bg = self._properties.get('disabledselectbackground') dis_sel_fg = self._properties.get('disabledselectforeground') dis_bg = self._properties.get('disableddaybackground') dis_fg = self._properties.get('disableddayforeground') cal_bg = self._properties.get('normalbackground') cal_fg = self._properties.get('normalforeground') hd_bg = self._properties.get("headersbackground") hd_fg = self._properties.get("headersforeground") bg = self._properties.get('background') fg = self._properties.get('foreground') bc = self._properties.get('bordercolor') om_fg = self._properties.get('othermonthforeground') om_bg = self._properties.get('othermonthbackground') omwe_fg = self._properties.get('othermonthweforeground') omwe_bg = self._properties.get('othermonthwebackground') we_bg = self._properties.get('weekendbackground') we_fg = self._properties.get('weekendforeground') self.style.configure('main.%s.TFrame' % self._style_prefixe, background=bg) self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=bc) self.style.configure('main.%s.TLabel' % self._style_prefixe, background=bg, foreground=fg) self.style.configure('headers.%s.TLabel' % self._style_prefixe, background=hd_bg, foreground=hd_fg) self.style.configure('normal.%s.TLabel' % self._style_prefixe, background=cal_bg, foreground=cal_fg) self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=om_bg, foreground=om_fg) self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=omwe_bg, foreground=omwe_fg) self.style.configure('sel.%s.TLabel' % self._style_prefixe, background=sel_bg, foreground=sel_fg) self.style.configure('we.%s.TLabel' % self._style_prefixe, background=we_bg, foreground=we_fg) size = max(self._header_font.actual()["size"], 10) self.style.configure('R.%s.TButton' % self._style_prefixe, background=bg, arrowcolor=fg, arrowsize=size, bordercolor=bg, relief="flat", lightcolor=bg, darkcolor=bg) self.style.configure('L.%s.TButton' % self._style_prefixe, background=bg, arrowsize=size, arrowcolor=fg, bordercolor=bg, relief="flat", lightcolor=bg, darkcolor=bg) self.style.map('R.%s.TButton' % self._style_prefixe, background=[('active', active_bg)], bordercolor=[('active', active_bg)], relief=[('active', 'flat')], darkcolor=[('active', active_bg)], lightcolor=[('active', active_bg)]) self.style.map('L.%s.TButton' % self._style_prefixe, background=[('active', active_bg)], bordercolor=[('active', active_bg)], relief=[('active', 'flat')], darkcolor=[('active', active_bg)], lightcolor=[('active', active_bg)]) self.style.map('sel.%s.TLabel' % self._style_prefixe, background=[('disabled', dis_sel_bg)], foreground=[('disabled', dis_sel_fg)]) self.style.map(self._style_prefixe + '.TLabel', background=[('disabled', dis_bg)], foreground=[('disabled', dis_fg)]) def _display_calendar(self): """Display the days of the current month (the one in self._date).""" year, month = self._date.year, self._date.month # update header text (Month, Year) header = self._month_names[month] self._header_month.configure(text=header.title()) self._header_year.configure(text=str(year)) # update calendar shown dates cal = self._cal.monthdatescalendar(year, month) next_m = month + 1 y = year if next_m == 13: next_m = 1 y += 1 if len(cal) < 6: if cal[-1][-1].month == month: i = 0 else: i = 1 cal.append(self._cal.monthdatescalendar(y, next_m)[i]) if len(cal) < 6: cal.append(self._cal.monthdatescalendar(y, next_m)[i + 1]) week_days = {i: 'normal' for i in range(7)} week_days[5] = 'we' week_days[6] = 'we' prev_m = (month - 2) % 12 + 1 months = {month: '.%s.TLabel' % self._style_prefixe, next_m: '_om.%s.TLabel' % self._style_prefixe, prev_m: '_om.%s.TLabel' % self._style_prefixe} week_nb = self._date.isocalendar()[1] modulo = max(week_nb, 52) for i_week in range(6): self._week_nbs[i_week].configure(text=str((week_nb + i_week - 1) % modulo + 1)) for i_day in range(7): style = week_days[i_day] + months[cal[i_week][i_day].month] txt = str(cal[i_week][i_day].day) self._calendar[i_week][i_day].configure(text=txt, style=style) self._display_selection() def _display_selection(self): """Highlight selected day.""" if self._sel_date is not None: year = self._sel_date.year if year == self._date.year: _, w, d = self._sel_date.isocalendar() wn = self._date.isocalendar()[1] w -= wn w %= max(52, wn) if 0 <= w and w < 6: self._calendar[w][d - 1].configure(style='sel.%s.TLabel' % self._style_prefixe) def _remove_selection(self): """Remove highlight of selected day.""" if self._sel_date is not None: year, month = self._sel_date.year, self._sel_date.month if year == self._date.year: _, w, d = self._sel_date.isocalendar() wn = self._date.isocalendar()[1] w -= wn w %= max(52, wn) if w >= 0 and w < 6: if month == self._date.month: if d < 6: self._calendar[w][d - 1].configure(style='normal.%s.TLabel' % self._style_prefixe) else: self._calendar[w][d - 1].configure(style='we.%s.TLabel' % self._style_prefixe) else: if d < 6: self._calendar[w][d - 1].configure(style='normal_om.%s.TLabel' % self._style_prefixe) else: self._calendar[w][d - 1].configure(style='we_om.%s.TLabel' % self._style_prefixe) # --- callbacks def _next_month(self): """Display the next month.""" year, month = self._date.year, self._date.month self._date = self._date + \ self.timedelta(days=calendar.monthrange(year, month)[1]) # if month == 12: # # don't increment year # self._date = self._date.replace(year=year) self._display_calendar() def _prev_month(self): """Display the previous month.""" self._date = self._date - self.timedelta(days=1) self._date = self._date.replace(day=1) self._display_calendar() def _next_year(self): """Display the next year.""" year = self._date.year self._date = self._date.replace(year=year + 1) self._display_calendar() def _prev_year(self): """Display the previous year.""" year = self._date.year self._date = self._date.replace(year=year - 1) self._display_calendar() # --- bindings def _on_click(self, event): """Select the day on which the user clicked.""" if self._properties['state'] is 'normal': label = event.widget day = label.cget("text") style = label.cget("style") if style in ['normal_om.%s.TLabel' % self._style_prefixe, 'we_om.%s.TLabel' % self._style_prefixe]: if label in self._calendar[0]: self._prev_month() else: self._next_month() if day: day = int(day) year, month = self._date.year, self._date.month self._remove_selection() self._sel_date = self.date(year, month, day) self._display_selection() if self._textvariable is not None: self._textvariable.set(self.format_date(self._sel_date)) self.event_generate("<<CalendarSelected>>") def format_date(self, date=None): """Convert date (datetime.date) to a string in the locale (short format).""" return format_date(date, 'short', self._properties['locale']) def parse_date(self, date): """Parse string date in the locale format and return the corresponding datetime.date.""" return parse_date(date, self._properties['locale']) # --- selection handling def selection_get(self): """ Return currently selected date (datetime.date instance). Always return None if selectmode is "none". """ if self._properties.get("selectmode") is "day": return self._sel_date else: return None def selection_set(self, date): """ Set the selection to date. date can be either a datetime.date instance or a string corresponding to the date format "%x" in the Calendar locale. Do nothing if selectmode is "none". """ if self._properties.get("selectmode") is "day" and self._properties['state'] is 'normal': if date is None: self._remove_selection() self._sel_date = None if self._textvariable is not None: self._textvariable.set('') else: if isinstance(date, self.date): self._sel_date = date else: try: self._sel_date = self.parse_date(date) except Exception: raise ValueError("%r is not a valid date." % date) if self._textvariable is not None: self._textvariable.set(self.format_date(self._sel_date)) self._date = self._sel_date.replace(day=1) self._display_calendar() self._display_selection() def get_date(self): """Return selected date as string.""" if self._sel_date is not None: return self.format_date(self._sel_date) else: return "" # --- other methods def keys(self): """Return a list of all resource names of this widget.""" return list(self._properties.keys()) def cget(self, key): """Return the resource value for a KEY given as string.""" return self[key] def configure(self, **kw): """ Configure resources of a widget. The values for resources are specified as keyword arguments. To get an overview about the allowed keyword arguments call the method keys. """ for item, value in kw.items(): self[item] = value def config(self, **kw): """ Configure resources of a widget. The values for resources are specified as keyword arguments. To get an overview about the allowed keyword arguments call the method keys. """ for item, value in kw.items(): self[item] = value
def __setitem__(self, key, value): if key not in self._properties: raise AttributeError("Calendar object has no attribute %s." % key) elif key is "locale": raise AttributeError("This attribute cannot be modified.") else: if key is "selectmode": if value is "none": for week in self._calendar: for day in week: day.unbind("<1>") elif value is "day": for week in self._calendar: for day in week: day.bind("<1>", self._on_click) else: raise ValueError("'selectmode' option should be 'none' or 'day'.") elif key is 'textvariable': if self._sel_date is not None: if value is not None: value.set(self.format_date(self._sel_date)) try: if self._textvariable is not None: self._textvariable.trace_remove('write', self._textvariable_trace_id) if value is not None: self._textvariable_trace_id = value.trace_add('write', self._textvariable_trace) except AttributeError: if self._textvariable is not None: self._textvariable.trace_vdelete('w', self._textvariable_trace_id) if value is not None: value.trace('w', self._textvariable_trace) self._textvariable = value elif key is 'showweeknumbers': if value: for wlabel in self._week_nbs: wlabel.grid() else: for wlabel in self._week_nbs: wlabel.grid_remove() elif key is 'borderwidth': try: bd = int(value) self._cal_frame.pack_configure(padx=bd, pady=bd) except ValueError: raise ValueError('expected integer for the borderwidth option.') elif key is 'state': if value not in ['normal', 'disabled']: raise ValueError("bad state '%s': must be disabled or normal" % value) else: state = '!' * (value == 'normal') + 'disabled' self._l_year.state((state,)) self._r_year.state((state,)) self._l_month.state((state,)) self._r_month.state((state,)) for child in self._cal_frame.children.values(): child.state((state,)) elif key is "font": font = Font(self, value) prop = font.actual() self._font.configure(**prop) prop["size"] += 1 self._header_font.configure(**prop) size = max(prop["size"], 10) self.style.configure('R.%s.TButton' % self._style_prefixe, arrowsize=size) self.style.configure('L.%s.TButton' % self._style_prefixe, arrowsize=size) elif key is "normalbackground": self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value) self.style.configure('normal.%s.TLabel' % self._style_prefixe, background=value) self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "normalforeground": self.style.configure('normal.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "bordercolor": self.style.configure('cal.%s.TFrame' % self._style_prefixe, background=value) elif key is "othermonthforeground": self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "othermonthbackground": self.style.configure('normal_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "othermonthweforeground": self.style.configure('we_om.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "othermonthwebackground": self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "selectbackground": self.style.configure('sel.%s.TLabel' % self._style_prefixe, background=value) elif key is "selectforeground": self.style.configure('sel.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "disabledselectbackground": self.style.map('sel.%s.TLabel' % self._style_prefixe, background=[('disabled', value)]) elif key is "disabledselectforeground": self.style.map('sel.%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)]) elif key is "disableddaybackground": self.style.map('%s.TLabel' % self._style_prefixe, background=[('disabled', value)]) elif key is "disableddayforeground": self.style.map('%s.TLabel' % self._style_prefixe, foreground=[('disabled', value)]) elif key is "weekendbackground": self.style.configure('we.%s.TLabel' % self._style_prefixe, background=value) self.style.configure('we_om.%s.TLabel' % self._style_prefixe, background=value) elif key is "weekendforeground": self.style.configure('we.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "headersbackground": self.style.configure('headers.%s.TLabel' % self._style_prefixe, background=value) elif key is "headersforeground": self.style.configure('headers.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "background": self.style.configure('main.%s.TFrame' % self._style_prefixe, background=value) self.style.configure('main.%s.TLabel' % self._style_prefixe, background=value) self.style.configure('R.%s.TButton' % self._style_prefixe, background=value, bordercolor=value, lightcolor=value, darkcolor=value) self.style.configure('L.%s.TButton' % self._style_prefixe, background=value, bordercolor=value, lightcolor=value, darkcolor=value) elif key is "foreground": self.style.configure('R.%s.TButton' % self._style_prefixe, arrowcolor=value) self.style.configure('L.%s.TButton' % self._style_prefixe, arrowcolor=value) self.style.configure('main.%s.TLabel' % self._style_prefixe, foreground=value) elif key is "cursor": ttk.Frame.configure(self, cursor=value) self._properties[key] = value
def __setitem__(self, key, value): if key not in self._properties: raise AttributeError("Calendar object has no attribute %s." % key) elif key is "locale": raise AttributeError("This attribute cannot be modified.") else: if key is "selectmode": if value is "none": for week in self._calendar: for day in week: day.unbind("<1>") elif value is "day": for week in self._calendar: for day in week: day.bind("<1>", self._on_click) else: raise ValueError( "'selectmode' option should be 'none' or 'day'.") elif key is 'borderwidth': try: bd = int(value) self._cal_frame.pack_configure(padx=bd, pady=bd) except ValueError: raise ValueError( 'expected integer for the borderwidth option.') elif key is "font": font = Font(self, value) prop = font.actual() self._font.configure(**prop) prop["size"] += 1 self._header_font.configure(**prop) size = max(prop["size"], 10) self.style.configure(self._style_prefixe + '.R.TButton', arrowsize=size) self.style.configure(self._style_prefixe + '.L.TButton', arrowsize=size) elif key is "normalbackground": self.style.configure(self._style_prefixe + '.cal.TFrame', background=value) self.style.configure(self._style_prefixe + '.normal.TLabel', background=value) self.style.configure(self._style_prefixe + '.normal_om.TLabel', background=value) elif key is "normalforeground": self.style.configure(self._style_prefixe + '.normal.TLabel', foreground=value) elif key is "bordercolor": self.style.configure(self._style_prefixe + '.cal.TFrame', background=value) elif key is "othermonthforeground": self.style.configure(self._style_prefixe + '.normal_om.TLabel', foreground=value) elif key is "othermonthbackground": self.style.configure(self._style_prefixe + '.normal_om.TLabel', background=value) elif key is "othermonthweforeground": self.style.configure(self._style_prefixe + '.we_om.TLabel', foreground=value) elif key is "othermonthwebackground": self.style.configure(self._style_prefixe + '.we_om.TLabel', background=value) elif key is "selectbackground": self.style.configure(self._style_prefixe + '.sel.TLabel', background=value) elif key is "selectforeground": self.style.configure(self._style_prefixe + '.sel.TLabel', foreground=value) elif key is "weekendbackground": self.style.configure(self._style_prefixe + '.we.TLabel', background=value) self.style.configure(self._style_prefixe + '.we_om.TLabel', background=value) elif key is "weekendforeground": self.style.configure(self._style_prefixe + '.we.TLabel', foreground=value) elif key is "headersbackground": self.style.configure(self._style_prefixe + '.headers.TLabel', background=value) elif key is "headersforeground": self.style.configure(self._style_prefixe + '.headers.TLabel', foreground=value) elif key is "background": self.style.configure(self._style_prefixe + '.main.TFrame', background=value) self.style.configure(self._style_prefixe + '.main.TLabel', background=value) self.style.configure(self._style_prefixe + '.R.TButton', background=value, bordercolor=value, lightcolor=value, darkcolor=value) self.style.configure(self._style_prefixe + '.L.TButton', background=value, bordercolor=value, lightcolor=value, darkcolor=value) elif key is "foreground": self.style.configure(self._style_prefixe + '.R.TButton', arrowcolor=value) self.style.configure(self._style_prefixe + '.L.TButton', arrowcolor=value) self.style.configure(self._style_prefixe + '.main.TLabel', foreground=value) elif key is "cursor": ttk.Frame.configure(self, cursor=value) self._properties[key] = value
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('<<ListboxSelect>>', self.update_entry_family) self.list_size.bind('<<ListboxSelect>>', self.update_entry_size, add=True) self.list_family.bind("<KeyPress>", self.keypress) self.entry_family.bind("<Return>", self.change_font_family) self.entry_family.bind("<Tab>", self.tab) self.entry_size.bind("<Return>", self.change_font_size) self.entry_family.bind("<Down>", self.down_family) self.entry_size.bind("<Down>", self.down_size) self.entry_family.bind("<Up>", self.up_family) self.entry_size.bind("<Up>", self.up_size) # bind Ctrl+A to select all instead of go to beginning self.bind_class("TEntry", "<Control-a>", 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('<<ListboxSelect>>') 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('<<ListboxSelect>>') 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('<<ListboxSelect>>') 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('<<ListboxSelect>>') 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()
class FontChooser(Toplevel): """ Font chooser toplevel """ def __init__(self, master, font_dict={}, text="Abcd", title="Font Chooser", **kwargs): """ Create a new FontChooser instance. font: dictionnary, like the one returned by the .actual method of a Font object {'family': 'DejaVu Sans', 'overstrike':False, 'size': 12, 'slant': 'italic' or 'roman', 'underline': False, 'weight': 'bold' or 'normal'} text: text to be displayed in the preview label title: window title **kwargs: 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["family"] = font_dict.get("family", self.fonts[0].replace('\ ', ' ')) font_dict["size"] = font_dict.get("size", 10) # Widgets creation 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_size = StringVar(self) self.entry_family = Entry(self, width=max_length, validate="key", validatecommand=(self._validate_family, "%d", "%S", "%i", "%s", "%V")) 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") entry_size.insert(0, font_dict["size"]) i = self.fonts.index(self.entry_family.get().replace(" ", "\ ")) self.list_family.selection_clear(0, "end") self.list_family.selection_set(i) self.list_family.see(i) i = self.sizes.index(entry_size.get()) self.list_size.selection_clear(0, "end") self.list_size.selection_set(i) self.list_size.see(i) self.entry_family.grid(row=0, column=0, sticky="ew", pady=(10, 1), padx=(10, 0)) 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('<<ListboxSelect>>', self.update_entry_family) self.list_size.bind('<<ListboxSelect>>', self.update_entry_size, add=True) self.list_family.bind("<KeyPress>", self.keypress) self.entry_family.bind("<Return>", self.change_font_family) self.entry_family.bind("<Tab>", self.tab) entry_size.bind("<Return>", self.change_font_size) self.entry_family.bind("<Down>", self.down_family) entry_size.bind("<Down>", self.down_size) self.entry_family.bind("<Up>", self.up_family) entry_size.bind("<Up>", self.up_size) # bind Ctrl+A to select all instead of go to beginning self.bind_class("TEntry", "<Control-a>", self.select_all) self.update_idletasks() self.grab_set() self.entry_family.focus_set() self.lift() def select_all(self, event): event.widget.selection_range(0, "end") def keypress(self, event): 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): try: txt = self.entry_family.get().replace(" ", "\ ") l = [i for i in self.fonts if i[:len(txt)] == txt] if l: self.list_family.selection_clear(0, "end") i = self.fonts.index(l[0]) if i > 0: self.list_family.selection_set(i - 1) self.list_family.see(i - 1) else: i = len(self.fonts) self.list_family.see(i - 1) self.list_family.select_set(i - 1) except TclError: i = len(self.fonts) self.list_family.see(i - 1) self.list_family.select_set(i - 1) self.list_family.event_generate('<<ListboxSelect>>') def up_size(self, event): try: s = self.var_size.get() i = self.sizes.index(s) self.list_size.selection_clear(0, "end") if i > 0: self.list_size.selection_set(i - 1) self.list_size.see(i - 1) else: 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('<<ListboxSelect>>') def down_family(self, event): try: txt = self.entry_family.get().replace(" ", "\ ") l = [i for i in self.fonts if i[:len(txt)] == txt] if l: self.list_family.selection_clear(0, "end") i = self.fonts.index(l[0]) if i < len(self.fonts) - 1: self.list_family.selection_set(i + 1) self.list_family.see(i + 1) else: self.list_family.see(0) self.list_family.select_set(0) except TclError: self.list_family.selection_set(0) self.list_family.event_generate('<<ListboxSelect>>') def down_size(self, event): try: s = self.var_size.get() i = self.sizes.index(s) 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('<<ListboxSelect>>') def toggle_bold(self): b = self.var_bold.get() self.preview_font.configure(weight=["normal", "bold"][b]) def toggle_italic(self): b = self.var_italic.get() self.preview_font.configure(slant=["roman", "italic"][b]) def toggle_underline(self): b = self.var_underline.get() self.preview_font.configure(underline=b) def toggle_overstrike(self): b = self.var_overstrike.get() self.preview_font.configure(overstrike=b) def change_font_family(self, event=None): family = self.entry_family.get() if family.replace(" ", "\ ") in self.fonts: self.preview_font.configure(family=family) def change_font_size(self, event=None): 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] if l: i = self.sizes.index(l[0]) 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): 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 path entry with existing folder/file 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): # 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): # 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): self.res = self.preview_font.actual() self.quit() def get_res(self): return self.res def quit(self): self.destroy()