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 _schedule(self):
self._unschedule()
self._id = self._widget.after(self._delay, self._show)
[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 _cursorPos(self, widget):
while not widget.master is None:
widget = widget.master
return widget.winfo_pointerxy()