Module tk_steroids.elements

Functions

def main()

Classes

class BufferShower (parent, string_buffer, max_entries=100)

Redirect any string buffer to be printed on this buffer reader. Bit like a non-interactive console window.

string_buffer Like StringIO, or sys.stdout

Expand source code
class BufferShower(tk.Frame):
    '''
    Redirect any string buffer to be printed on this buffer reader.
    Bit like a non-interactive console window.
    '''
    def __init__(self, parent, string_buffer, max_entries=100):
        '''
        string_buffer       Like StringIO, or sys.stdout
        '''
        tk.Frame.__init__(self, parent)

        self.parent = parent    
        self.string_buffer = string_buffer
        self.max_entries = max_entries
        
        self.entries = 0
        self.offset = 0

        self.text = tkinter.scrolledtext.ScrolledText(self)
        self.text.grid()
        
        self.parent.after(20, self.callback)
        
    def callback(self):
        self.string_buffer.seek(self.offset)

        for line in self.string_buffer:

            if self.entries > self.max_entries:
                self.text.delete('1.0','2.0')

            self.text.insert(tk.END, line)
            self.text.yview(tk.END)
            self.entries += 1
        
        self.offset = self.string_buffer.tell()

        self.parent.after(20, self.callback)

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Methods

def callback(self)
class ButtonsFrame (parent, button_names, button_commands, title='', label='', horizontal=True)

If you just need a frame with simply buttons (with a callback) next to each other, use this widget.

Attributes

buttons : list of objects
Tkinter button objects
label : object or None
If label given at init, store the tk.Label object in this attibute

Arguments

horizontal : bool
If True, grid buttons horizontally. If False, grid vertically.
title : string
If set, init using LabelFrame that encloses the buttons and use this text (title) as the label.
label : string
Alternative or complementary to the title option, just adds a tk.Label as the first button (if avoiding the LabelFrame box is desired).
Expand source code
class ButtonsFrame(tk.Frame):
    '''
    If you just need a frame with simply buttons (with a callback) next to each other,
    use this widget.
    
    Attributes
    ----------
    buttons : list of objects
        Tkinter button objects
    label : object or None
        If label given at init, store the tk.Label object in this attibute
    '''

    def __init__(self, parent, button_names, button_commands,
            title='', label='', horizontal=True):
        '''
        Arguments
        ---------
        horizontal : bool
            If True, grid buttons horizontally. If False, grid vertically.
        title : string
            If set, init using LabelFrame that encloses the buttons and
            use this text (title) as the label.
        label : string
            Alternative or complementary to the title option, just adds a tk.Label
            as the first button (if avoiding the LabelFrame box is desired).
        '''
        tk.Frame.__init__(self, parent)
        self.parent = parent
        
        if title:
            target = tk.LabelFrame(self, text=title)
            target.grid()
        else:
            target = self

        if label:
            self.label = tk.Label(self, text=label)
            if horizontal:
                self.label.grid(row=1, column=0)
            else:
                self.label.grid(row=0, column=1)
        else:
            self.label = None

        self.buttons = []

        for i_button, (name, command) in enumerate(zip(button_names, button_commands)):
            button = tk.Button(target, text=name, command=command)
            
            if horizontal:
                button.grid(row=1, column=i_button+1)
            else:
                button.grid(row=i_button+1, column=1)

            self.buttons.append(button)


    def get_buttons(self):
        '''
        Returns the initialized buttons in the order that the buttons_kwargs
        were delivered in the ButtonsFrame constructor.
        '''
        return self.buttons

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Methods

def get_buttons(self)

Returns the initialized buttons in the order that the buttons_kwargs were delivered in the ButtonsFrame constructor.

class ColorExplanation (parent, colors, help_strings)

If colors were used in the GUI, this widget can be used easily to create help texts to explain meaning of the colors.

Construct a frame widget with the parent MASTER.

Valid resource names: background, bd, bg, borderwidth, class, colormap, container, cursor, height, highlightbackground, highlightcolor, highlightthickness, relief, takefocus, visual, width.

Expand source code
class ColorExplanation(tk.Frame):
    '''
    If colors were used in the GUI, this widget can be used easily to
    create help texts to explain meaning of the colors.
    '''

    def __init__(self, parent, colors, help_strings):
        tk.Frame.__init__(self, parent)

        for i_row, (color, string) in enumerate(zip(colors, help_strings)):
            tk.Canvas(self, width=30, height=15, bg=color).grid(row=i_row, column=0, sticky='W')
            tk.Label(self, text=string, font=('System', 8)).grid(row=i_row, column=1, sticky='W')

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid
class DropdownList (parent, options, fancynames=None, label=None, default=None, callback=None, **kwargs)

A drop-in replacement for TickboxFrame using tkinter's OptionMenu (looks just like OptionMenu)

Attributes

option_menu : object
Underlying tkinter OptionMenu object
label : object
Underlying tkinter Label object (if label was specified at init)

Construct a frame widget with the parent MASTER.

Valid resource names: background, bd, bg, borderwidth, class, colormap, container, cursor, height, highlightbackground, highlightcolor, highlightthickness, relief, takefocus, visual, width.

Expand source code
class DropdownList(tk.Frame):
    '''
    A drop-in replacement for TickboxFrame using tkinter's OptionMenu
    (looks just like OptionMenu)

    Attributes
    ----------
    option_menu : object
        Underlying tkinter OptionMenu object
    label : object
        Underlying tkinter Label object (if label was specified at init)
    '''

    def __init__(self, parent, options, fancynames=None, label=None,
            default=None, callback=None, **kwargs):
        
        tk.Frame.__init__(self, parent)
        
        self.__options = options
        
        self.columnconfigure(2, weight=1)
        self.rowconfigure(1, weight=1)
   
        # Check fancynames to show
        if fancynames is None:
            fancynames = options
        else:
            if len(fancynames) != len(options):
                raise ValueError('options and fancynames different lengths, {} vs {}'.format(
                    len(fancynames), len(options)))
        
        self._fancynames = fancynames

        self._state = tk.StringVar(self)
        self._state.set(fancynames[0])
        if callback is not None:
            if callable(callback):
                self._state.trace('w', lambda *args: callback())
            else:
                raise ValueError('callback has to be callable or none, now {}'.format(callback))

        self.option_menu = tk.OptionMenu(self, self._state, *fancynames)
        self.option_menu.grid(row=1, column=2, sticky='NSWE')

        if label:
            self.label = tk.Label(self, text=label)
            self.label.grid(row=1, column=1, sticky='NSWE')
    
    @property
    def states(self):
        index = self._fancynames.index(self._state.get())
        current = self.__options[index]
        return {option: current == option for option in self.__options}

    @property
    def ticked(self):
        '''
        Returns a list of one item, the current selection.
        '''
        index = self._fancynames.index(self._state.get())
        return [self.__options[index]]

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Instance variables

prop states
Expand source code
@property
def states(self):
    index = self._fancynames.index(self._state.get())
    current = self.__options[index]
    return {option: current == option for option in self.__options}
prop ticked

Returns a list of one item, the current selection.

Expand source code
@property
def ticked(self):
    '''
    Returns a list of one item, the current selection.
    '''
    index = self._fancynames.index(self._state.get())
    return [self.__options[index]]
class Listbox (parent, selections, callback, maintain_selected=True)

Tkinter's Listbox and Scrollbar wrapped for convienece.

At the init, it takes in a list of selectable options, and a callback function. When the user selects and item, it evokes the callback that receives the user selection (one of the selectable options) as the input (or None if no selection).

Attributes

selections : list of strings
Items that show up in the listbox
callback : callable
The callback function
parent : object
Parent widget
listbox : object
Tkinter's Listbox widget
scrollbar : object
Tkinter's Scrollbar widget
maintain_selected : bool
If true, clicking other Listboxes or widgets does not make the current selection to None (deselecting the selected)
Expand source code
class Listbox(tk.Frame):
    '''Tkinter's Listbox and Scrollbar wrapped for convienece.
    
    At the init, it takes in a list of selectable options, and a callback function.
    When the user selects and item, it evokes the callback that receives
    the user selection (one of the selectable options) as the input
    (or None if no selection).
    
    Attributes
    ----------
    selections : list of strings
        Items that show up in the listbox
    callback : callable
        The callback function
    parent : object
        Parent widget
    listbox : object
        Tkinter's Listbox widget
    scrollbar : object
        Tkinter's Scrollbar widget
    '''

    def __init__(self, parent, selections, callback, maintain_selected=True):
        '''
        maintain_selected : bool
            If true, clicking other Listboxes or widgets does not make the current
            selection to None (deselecting the selected)
        '''
        
        tk.Frame.__init__(self, parent)
        self.parent = parent

        
        self.maintain_selected = maintain_selected

        self.listbox = tk.Listbox(self, height=20)
        self.listbox.grid(sticky='NSEW')
       
        self.scrollbar= tk.Scrollbar(self, orient='vertical', command=self.listbox.yview)
        self.scrollbar.grid(row=0, column=1, sticky='NS')
        
        self.listbox.config(yscrollcommand=self.scrollbar.set)


        self.set_selections(selections) # self.selections = selections
        self.callback = callback
        
        self.listbox.bind('<<ListboxSelect>>', self._call_callback)
        
        # Make the listbox to stretch in North-South to take all the available space
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        
        self._previous_selection = None
        self._state_valid = True


    def _call_callback(self, *args):
        '''Validate selection and the callback and call back
        '''
        try:
            sel = self.listbox.curselection()[0]
            argument = self.selections[sel]
            self._previous_selection = argument
            self._state_valid = True
        except:
            argument = None

        if not argument is None and callable(self.callback):
            self.callback(self.selections[sel])



    def set_selections(self, selections, colors=None):
        '''Reset the selectables

        Options
        -------
        selections : list of strings
            
        colors : list
            A list of valid tkinter colors. It sets
            the background color for each selectable in the Listbox.
        '''
        
        # Empty current as it may have old entries
        self.listbox.delete(0, tk.END)
        
        self.selections = selections
        
        for i_item, item in enumerate(self.selections):
            self.listbox.insert(tk.END, item)
            
            if colors:
                self.listbox.itemconfig(i_item, bg=colors[i_item])


    def disable(self):
        '''Makes the listbox's state unselectable
        '''
        self.listbox.configure(state=tk.DISABLED)


    def enable(self):
        '''Makes the listbox's state selectable
        '''
        self.listbox.configure(state=tk.NORMAL)

    
    def get_current(self):
        '''Returns the current selection.

        Returns None if no selection has been made.
        '''
        if not self._state_valid:
            return None

        try:
            sel = self.listbox.curselection()[0]
            return self.selections[sel]
        except:
            return self._previous_selection

    @property
    def current(self):
        '''
        current : string
            The current selection
        '''
        return self.get_current()

    
    @current.setter
    def current(self, value):
        if value is None:
            self._state_valid = False
            return

        if value not in self.selections:
            raise ValueError(f'"{value}" not in the selections {self.selections}')
        index = self.selections.index(value)
        self.listbox.select_set(index)

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Instance variables

prop current

current : string The current selection

Expand source code
@property
def current(self):
    '''
    current : string
        The current selection
    '''
    return self.get_current()

Methods

def disable(self)

Makes the listbox's state unselectable

def enable(self)

Makes the listbox's state selectable

def get_current(self)

Returns the current selection.

Returns None if no selection has been made.

def set_selections(self, selections, colors=None)

Reset the selectables

Options

selections : list of strings

colors : list A list of valid tkinter colors. It sets the background color for each selectable in the Listbox.

class SliderFrame (parent, options, fancynames=None, defaults=None, ncols=1, ranges=None, default_range=(0, 1), resolutions=None, default_resolution=0.01)

Multiple sliders (similar to TickboxFrame)

Attributes

options : list
Names of the variables that the sliders control
labels : list
Tkinter Label widgets
sliders : list
Tkinter Scale widgets

Options

parent : object Tkinter parent widget options : list of strings Names of the variables that the sliders control fancynames : list of strings, or None Optional, "fancy" names that are shown to the user defaults : list or None Slider default values ncols : int Reserved, not yet implemented. ranges : list of tuples Slider specific ranges (min, max) or None for each slider. default_range : tuple of numerical values Default (min, max) range resolutions : list of numerical values Slider specific resolutions or None for each slider. default_resolution : numerical Default slider resolution

Expand source code
class SliderFrame(tk.Frame):
    '''
    Multiple sliders (similar to TickboxFrame)
    
    Attributes
    ----------
    options : list
        Names of the variables that the sliders control
    labels : list
        Tkinter Label widgets
    sliders : list
        Tkinter Scale widgets
    '''
    def __init__(self, parent, options, fancynames=None, defaults=None, ncols=1,
            ranges=None, default_range=(0,1),
            resolutions=None, default_resolution=0.01):
        '''
        Options
        -------
        parent : object
            Tkinter parent widget
        options : list of strings
            Names of the variables that the sliders control
        fancynames : list of strings, or None
            Optional, "fancy" names that are shown to the user
        defaults : list or None
            Slider default values
        ncols : int
            Reserved, not yet implemented.
        ranges : list of tuples
            Slider specific ranges (min, max) or None for each slider.
        default_range : tuple of numerical values
            Default (min, max) range
        resolutions : list of numerical values
            Slider specific resolutions or None for each slider.
        default_resolution : numerical
            Default slider resolution
        '''
        tk.Frame.__init__(self, parent)
        self.grid_columnconfigure(1, weight=1)
 
        self.options = options
        self.labels = []
        self.sliders = []

        for i_row, name in enumerate(options):
            
            if fancynames and fancynames[i_row]:
                fancyname = fancynames[i_row]
            else:
                fancyname = name

            label = tk.Label(self, text=fancyname)
            label.grid(row=i_row, column=0)

            if ranges and ranges[i_row]:
                A, B = ranges[i_row]
            else:
                A, B = default_range

            if resolutions and resolutions[i_row]:
                resolution = resolutions[i_row]
            else:
                resolution = default_resolution

            slider = tk.Scale(self, from_=A, to=B, orient=tk.HORIZONTAL,
                    resolution=resolution)
            slider.grid(row=i_row, column=1, sticky='WE')

            if defaults and defaults[i_row]:
                slider.set(defaults[i_row])

            self.labels.append(label)
            self.sliders.append(slider)


    @property
    def states(self):
        '''
        Returns the slider values dictionary.
        Keys are slider names (options) and items are slider values.
        '''
        return {option: slider.get() for option, slider in zip(self.options, self.sliders)}

    
    @states.setter
    def states(self, s):
        for slider, option in zip(self.sliders, self.options):
            value = s.get(option, None)
            if value is not None:
                slider.set(value)

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Instance variables

prop states

Returns the slider values dictionary. Keys are slider names (options) and items are slider values.

Expand source code
@property
def states(self):
    '''
    Returns the slider values dictionary.
    Keys are slider names (options) and items are slider values.
    '''
    return {option: slider.get() for option, slider in zip(self.options, self.sliders)}
class Tabs (parent, tab_names, elements=None, draw_frame=False, on_select_callback=None)

Tabs widget. Can contain any tkinter widgets.

Attributes

i_current : int
Index of the currently selected tab.
buttons : list of objects
List of tk.Button instances.
pages : list of objects
A list of Tkinter widgets the tab holds.

Initializing the tabs.

Arguments

parent
Tkinter parent widget
tab_names
Human readable names, shown in the buttons
elements : None or list of classes

If None (by default), initializes tk.Frames as tabs. You can get these tk.Frames are in pages attribute.

Can also classes, that get initialized as this Tabs class as the sole argument.

draw_frame : bool
If True, draw an extra frame to confine the tabs
on_select_callback : callable
Callback that is executed just before changing the tab. Has to take in one argument that is new i_current (integer).
Expand source code
class Tabs(tk.Frame):
    '''
    Tabs widget. Can contain any tkinter widgets.

    Attributes
    ----------
    i_current : int
        Index of the currently selected tab.
    buttons : list of objects
        List of tk.Button instances.
    pages : list of objects
        A list of Tkinter widgets the tab holds.
    
    '''
    def __init__(self, parent, tab_names,
            elements=None, draw_frame=False,
            on_select_callback=None):
        '''
        Initializing the tabs.
        
        Arguments
        ---------
        parent
            Tkinter parent widget
        tab_names
            Human readable names, shown in the buttons
        elements : None or list of classes
            If None (by default), initializes tk.Frames as tabs.
            You can get these tk.Frames are in pages attribute.

            Can also classes, that get initialized as this Tabs class
            as the sole argument.
        draw_frame : bool
            If True, draw an extra frame to confine the tabs
        on_select_callback : callable
            Callback that is executed just before changing the tab.
            Has to take in one argument that is new i_current (integer).
        
        '''
        
        # Call init from LabelFrame if framing is wanted
        # Not sure if this can cause problems (when inheriting from tk.Frame)
        if draw_frame:
            tk.LabelFrame.__init__(self, parent)
        else:
            tk.Frame.__init__(self, parent)

        self.parent = parent

        self.on_select_callback = on_select_callback

        self.i_current = 0

        self.buttons = []
        self.pages = []


        buttons_frame = tk.Frame(self)
        buttons_frame.grid()

        if elements is None:
            elements = [tk.Frame for i_tab in tab_names]

        # Initialize content/elements
        for i_button, (name, element) in enumerate(zip(tab_names, elements)):

            initialized_element = element(self)
            self.pages.append(initialized_element)
            

            button = tk.Button(buttons_frame, text=name, command=lambda i_button=i_button: self.set_page(i_button))
            button.grid(row=0, column = i_button, sticky='N')
            self.buttons.append(button)
            

        self.pages[self.i_current].grid(row=1, columnspan=len(self.buttons), sticky='NSEW')
        
        self.grid_rowconfigure(1, weight=1)
        self.grid_columnconfigure(0, weight=1)
    
    @property
    def tabs(self):
        return self.pages

    def set_page(self, i_page):
        '''
        When button number i_button is pressed.
        '''
        # Update i_current and take i_old for now
        i_old = self.i_current
        self.i_current = i_page

        if self.on_select_callback is not None:
            self.on_select_callback(self.i_current)

        # Remove the previously gridded widget
        self.pages[i_old].grid_remove()

        # Grid the new widget
        self.pages[self.i_current].grid(row=1, columnspan=len(self.buttons), sticky='NSEW')

        # Change button reliefs (pressed)
        self.buttons[i_old].config(relief=tk.RAISED)
        self.buttons[i_page].config(relief=tk.SUNKEN)


    def get_elements(self):
        '''
        Returns the initialized elements which have to the Tab as their master/parent.
        '''
        return self.pages

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Instance variables

prop tabs
Expand source code
@property
def tabs(self):
    return self.pages

Methods

def get_elements(self)

Returns the initialized elements which have to the Tab as their master/parent.

def set_page(self, i_page)

When button number i_button is pressed.

class TickboxFrame (parent, options, fancynames=None, defaults=None, ncols=3, single_select=False, callback=None)

A series of tickboxes (Checkbuttons) and getting their True/False values.

Attributes

states : dict
True/False
ticked : list
self.states keys that have True value
checkbuttons : list
tk.Checkbutton objects
parent
Tkinter parent widget
options : list of strings
Names of the options
fancynames : list of strings
Names to show on the gui
defaults : list of bools
Start values, True for ticked and False for unticked
ncols : int
Number of columns
single_select : bool
If True, use Radiobuttons instead of Checkbuttons to only have one active selection at a time.
callback : callable
Executed when there's a change in the tickboxes. Gets the self.states dict as an input argument.
Expand source code
class TickboxFrame(tk.Frame):
    '''
    A series of tickboxes (Checkbuttons) and getting their True/False values.
    
    Attributes
    ----------
    states : dict
        True/False
    ticked : list
        self.states keys that have True value
    checkbuttons : list
        tk.Checkbutton objects
    '''

    def __init__(self, parent, options, fancynames=None, defaults=None, ncols=3,
            single_select=False,
            callback=None):
        '''
        parent
            Tkinter parent widget
        options : list of strings
            Names of the options
        fancynames : list of strings
            Names to show on the gui
        defaults : list of bools
            Start values, True for ticked and False for unticked
        ncols : int
            Number of columns
        single_select : bool
            If True, use Radiobuttons instead of Checkbuttons to only have
            one active selection at a time.
        callback : callable
            Executed when there's a change in the tickboxes.
            Gets the self.states dict as an input argument.
        '''
         
        tk.Frame.__init__(self, parent)
        self.parent = parent
        self._single_select = single_select 

        if single_select:
            intvar = tk.IntVar()
            self.__states = {option: intvar for option in options}
            self._option_names = options
            try:
                intvar.set(defaults.index(True))
            except:
                intvar.set(0)

        else:
            self.__states = {option: tk.IntVar() for option in options}
        
            if defaults is not None:
                for option, default in zip(options, defaults):
                    self.__states[option].set( int(default) ) 
            

        if fancynames is None:
            fancynames = {option: option for option in options}
        else:
            fancynames = {option: fancyname for option, fancyname in zip(options, fancynames)}
        
        if single_select:
            self.checkbuttons = [tk.Radiobutton(self, text=fancynames[option],
                variable=self.__states[option], command=callback,
                value=i_option) for i_option, option in enumerate(options)]
        else:
            self.checkbuttons = [tk.Checkbutton(self, text=fancynames[option],
                variable=self.__states[option], command=callback) for option in options]


        i_row = 1
        i_col = 1
        for button in self.checkbuttons:
            button.grid(row=i_row, column=i_col)
            
            i_col += 1
            if i_col > ncols:
                i_col = 1
                i_row += 1
    
    @property
    def states(self):
        if self._single_select:
            return {option: int(self.__states[option].get()) == i for i, option in enumerate(self._option_names)}
        else:
            return {option: bool(intvar.get()) for option, intvar in self.__states.items()}

    @states.setter
    def states(self, s):
        
        for option in self.__states.keys():
            value = s.get(option, None)
            if value is not None:
                self.__states[option].set(value)

    @property
    def ticked(self):
        return [s for s, b in self.states.items() if b]

Ancestors

  • tkinter.Frame
  • tkinter.Widget
  • tkinter.BaseWidget
  • tkinter.Misc
  • tkinter.Pack
  • tkinter.Place
  • tkinter.Grid

Instance variables

prop states
Expand source code
@property
def states(self):
    if self._single_select:
        return {option: int(self.__states[option].get()) == i for i, option in enumerate(self._option_names)}
    else:
        return {option: bool(intvar.get()) for option, intvar in self.__states.items()}
prop ticked
Expand source code
@property
def ticked(self):
    return [s for s, b in self.states.items() if b]