Package: ticklish-ui
Table of ContentsTicklish - Declarative style GUI programming in PythonGetting StartedNext StepsFeaturesWidgetsStreamsFuture DevelopmentContributingLicenseTicklish - Declarative style GUI programming in PythonTheticklish_uipackage is a wrapper around the tkinter and
tkinter.ttk widgets which aims to simplify GUI creation by allowing
users to specify the layout declaratively while decoupling GUI
creation from event binding.Ticklish works by wrapping the underlying widgets in factory objects
deferring actual widget creation until the entire layout has been
specified. Layouts are specified as rows of widgets which are laid
out from left to right. Once created, event streams are used to bind
actions to specific widgets.The following simple example creates a window which accepts some
input, prints it to the console when the OK button is clicked, and
closes the application when the Quit button is clicked.from ticklish_ui import *

# Define the layout.  An application can have any number of rows and
# rows can contain any number of widgets.
app = Application(
    'ticklish_ui_example',

    # .row1
    [Label('Enter some text below')],

    # .row2
    [Entry().options(name='entry')],

    # .row3
    [Button('OK').options(name='ok'), CloseButton('Quit')]
)

def print_input(event):
    entry = app.nametowidget('.row2.entry')
    print(entry.get())

# click captures all click events anywhere in the application.
click = app.get_event_stream('<ButtonRelease-1>')

# An event stream can then be filtered and bound to some action(s)
(click
 # Here we filter by the name of the widget clicked.
 .by_name('ok') 

 # And then map/bind an action to that event.
 .map(print_input)
)

app.mainloop()The use of event streams is optional. Users can retrieve widgets and
bind events and commands in a more traditional way if they
prefer. The following would also have worked in the above example.def print_input():
    entry = app.nametowidget('.row2.entry')
    print(entry.get())

ok_button = app.nametowidget('.row3.ok')
ok_button['command'] = print_input

# Or you can bind events.
#ok_button.bind('<ButtonRelease-1>', do_something)Most ticklish widgets are just straight wrappers for the underlying
widgets but additions have been made for convenience. For instance,
CloseButton in the above example is a button which automatically
calls the destory() method on the toplevel window that contains it.
Similarly, there are RadioGroup and CheckGroup widgets which allow
you to lay out whole sets of the corresponding buttons easily.The goal of ticklish is to simplify the creation and implementation
of GUIs without abstracting away any of their power.Getting StartedTo start usingticklish_uiinstall it from the Python Package Index
with pip:pip3 install ticklish_uiCheck that the install worked by running the following code either
from a file or the python interactive interpreter.import ticklish_ui as tui

tui.Application('MyApp').mainloop()You should get something that looks like this:Next StepsThemesTicklish is set up to use the ttk default theme out-of-the-box
which probably won't look that great. Once created, you can use
the application'sstyleproperty to change the theme.app = Application(
    'MyApp',
    # Rows...
)
app.style.theme_use('aqua') # Or whatever theme you're using
app.mainloop()Theaquatheme is used in the above screenshots but may not be
available on all systems.You can use thetheme viewerexample to see the themes available
on your system and then set one as above.Module DocumentationAn attempt has been made to make theticklish_uimodule
documentation as comprehensive as possible. It can be viewed in a
number of ways.With pydoc from the commandline:pydoc3 ticklish_ui.widgets.applicationWithhelp()from the python interactive interpreter:>>> import ticklish_ui
>>> help(ticklish_ui.events.EventStream)Or just by browsing thesource codeon github.The github repository also includes a number ofexamples.TutorialA more in-depth example implementing a simple application for
drawing graphs can be foundhere.FeaturesWidgetsThe following widgets are currently implemented. Widgets which are
marked asticklish_uiadditions are not part of the standard
tkinter/tkinter.ttk widgets sets andmayhave additional attributes
and behaviours in addition to those provided by the base widget.`ticklish_ui` nameBase widget`ticklish_ui` additionApplicationtkinter.TkyesButtontkinter.ttk.ButtonnoCanvastkinter.CanvasnoCheckGrouptkinter.ttk.FrameyesCheckbuttontkinter.ttk.CheckbuttonnoCloseButtontkinter.ttk.ButtonyesComboboxtkinter.ttk.ComboboxnoDropdowntkinter.ttk.Comboboxyes\*Entrytkinter.ttk.EntrynoFrametkinter.ttk.FramenoLabeltkinter.ttk.LabelnoLabelFrametkinter.ttk.LabelFramenoListboxtkinter.ttk.Treeviewyes\*Notebooktkinter.ttk.NotebooknoPanedWindowtkinter.ttk.PanedWindownoProgressbartkinter.ttk.ProgressbarnoRadioGrouptkinter.ttk.FrameyesRadiobuttontkinter.ttk.RadiobuttonnoScaletkinter.ttk.ScalenoScrollabletkinter.CanvasyesScrollbartkinter.ttk.ScrollbarnoSeparatortkinter.ttk.SeparatornoTexttkinter.TextnoTopleveltkinter.ToplevelnoTreeviewtkinter.ttk.Treeviewno*These widgets are additions in the sense that they use specific
settings to get a particular default behaviour but are otherwise
just wrappers around the base widget.Eventually ticklish will provide wrappers out-of-the-box for all
tkinter and tkinter.ttk widgets. Users can implement or wrap
additional widgets by subclassing the WidgetFactory or
ContainerFactory classes as needed.StreamsTicklish provides a very simple Stream construct. Data can be
inserted into a stream and will be acted on automatically before
being passed to any child streams if they exist. Child streams are
created by filtering and mapping existing streams. Filtering
determines what data is allowed into the stream; mapping, how the
data is handled and/or transformed.Here's a quick example:from ticklish_ui.events import Stream

base = Stream()

odd_stream = base.filter(lambda n: n % 2 == 1).map(lambda n: print(f'odd: {n}'))
even_stream = base.filter(lambda n: n % 2 == 0).map(lambda n: print(f'even: {n}'))

base.insert(1)
base.insert(2)
base.insert(3)
base.insert(4)
base.insert(5)
base.insert(6)
base.insert(7)
base.insert(8)
base.insert(9)
base.insert(10)RESULTS:odd: 1
even: 2
odd: 3
even: 4
odd: 5
even: 6
odd: 7
even: 8
odd: 9
even: 10Note that, although data is being inserted into thebasestream,
it's the child streams —odd_streamandeven_stream—
which are doing the actual work. If either of the mapped functions
returned a value then further filtering and mapping could be done
creating a whole pipeline of actions to be carried out
automatically any time a value is inserted into the base stream.The EventStream class provides default filters for dealing
specifically with tkinter events — filtering by the name of the
widget involved, for instance — but is otherwise just a regular
stream.Streams allow program authors to handle normal data and user
generated events in similar ways but are entirely optional.Future DevelopmentOn the todo list in no particular order:Allow merging streamsImplement the rest of the tkinter and tkinter.ttk widgetsAdd a way to declaratively define grid layoutsContributingFor detailed information on contributing toticklish_uiseeCONTRIBUTING.orgon github.Licenseticklish_uiis free software licensed under theBSD-3-Clause License.Changesv0.3.0(2021-03-13)ChoreAdds CHANGES.md to long_description for pypiUpdates README.org with newly added widgetsDocsAdds a more complex application menu exampleAdds Treeview exampleAdds an example for the Separator widgetFeatAdds Treeview widgetChanges menubar() to work with MenuSpecification objectsAdds MenuSpecification class for defining hierarchical menus.Adds the Separator widgetFixFixes Application.menubar() so nested menu entries are named properlyv0.2.0(2021-03-02)ChoreUpdate to version 0.2.0updates .gitignoreDocsAdds PanedWindow exampleAdds an example of NotebookAdds two examples using Scrollable widgetsAdds tags_example.pyAdds an example of the Text widgetAdds an example for scale widgetsAdds an example demonstrating virtual event user data.FeatAdds PanedWindow widgetAdds Notebook widgetAdds Scrollbar widget and Scrollable containerAdds tags option to all widgetsAdds wrapper class for the Text widgetAdds Scale widgetAdds progressbar widgetAllows user data with virtual events in event streams.FixMakes sure tags are applied to containers and not just contentsv0.1.3(2021-02-21)v0.1.2(2021-02-21)v0.1.1(2021-02-13)v0.1.0 (2021-02-13)