Source code for gui.controls

'''Provides custom Tkinter controls'''
import tkinter as tk
import tkinter.ttk as ttk

from config import GUIConfig

conf = GUIConfig()

[docs]class LabeledScale(tk.Frame): ''':class:`tkinter.ttk.Scale` and a :class:`tkinter.Spinbox` joined in a frame The :class:`~tkinter.ttk.Scale` in shown to the left of the :class:`~tkinter.Spinbox` :param root: Parent :class:`tkinter.Widget` :param font: :class:`~tkinter.font.Font` to use in the :class:`~tkinter.Spinbox` :param resolution: (:class:`int`) Number of decimal places to round stored and displayed value to ''' def __init__(self, root, font, resolution=2, **kwargs): super().__init__(root,background = 'white') self.columnconfigure(0, weight=1) self._res = resolution self._var = tk.IntVar() if resolution < 1 else tk.DoubleVar() self._scale = ttk.Scale(self, command=self._update, variable=self._var, **kwargs) self._scale.grid(row=0, column=0, sticky='ew', padx=(0, 10)) self._spinner = tk.Spinbox(self, command=self._update, textvariable=self._var, width=6, font=font, **kwargs) self._spinner.grid(row=0, column=1)
[docs] def _update(self, val=None): '''Callback method for both the :class:`~tkinter.Spinbox` and :class:`~tkinter.ttk.Scale` so that each can update the other, and the value can be properly formatted ''' if not val: val = self._var.get() self._var.set(('%.0' +str(self._res)+ 'f') % float(val))
[docs] def set(self, val): '''Set value of both the :class:`~tkinter.tk.Spinner` and :class:`~tkinter.ttk.Scale` :param val: :class:`float` to set values to ''' self._var.set(val)
[docs] def get(self): ''' :returns: :class:`float` - Value stored, rounded to specified resolution number of decimal places ''' return round(self._var.get(), self._res)
[docs]class ToolTip(object): '''Creates a tooltip that appears above the given widget when hovered :Authors: - Fuzzyman: http://voidspace.org.uk/python/weblog/arch_d7_2006_07_01.shtml#e387 - vegaseat: https://daniweb.com/programming/software-development/code/484591 - crxguy52: https://stackoverflow.com/a/36221216 :param widget: :class:`tkinter.Widget` to bind to :param text: (:class:`str`) Text content of the tooltip :param delay: (:class:`int`) Milliseconds before displaying tooltip on hover :param width: (:class:`int`) Maximum width of tooltip in characters ''' def __init__(self, widget, text='', delay=500, width=conf.TooltipWidth): self._delay = delay self._wrap = width self._widget = widget self.text = text self._widget.bind('<Enter>', self._enter) self._widget.bind('<Leave>', self._leave) self._widget.bind('<ButtonPress>', self._leave) self._id = None self._window = None
[docs] def _enter(self, event=None): self._schedule()
[docs] def _leave(self, event=None): self._unschedule() self._hide()
[docs] def _schedule(self): self._unschedule() self._id = self._widget.after(self._delay, self._show)
[docs] def _unschedule(self): if self._id: self._widget.after_cancel(self._id) self._id = None
[docs] def _show(self, event=None): (x, y) = self._cursorPos(self._widget) self._window = tk.Toplevel(self._widget) self._window.wm_overrideredirect(True) self._window.wm_geometry('+%d+%d' % (x +12, y +12)) label = ttk.Label(self._window, text=self.text, justify='left', background='white', relief='solid', borderwidth=1, wraplength=self._wrap) label.pack(ipadx=1)
[docs] def _hide(self): if self._window: self._window.destroy() self._window = None
[docs] def _cursorPos(self, widget): while not widget.master is None: widget = widget.master return widget.winfo_pointerxy()