Skip to main content

Table of Contents

  1. Ticklish - Declarative style GUI programming in Python
    1. Getting Started
      1. Next Steps
    2. Features
      1. Widgets
      2. Streams
    3. Future Development
    4. Contributing
    5. License

Ticklish - Declarative style GUI programming in Python

The ticklish_ui package 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()

img

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 Started

To start using ticklish_ui install it from the Python Package Index with pip:

pip3 install ticklish_ui

Check 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:

img

Next Steps

  1. Themes

    Ticklish 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's style property to change the theme.

    app = Application(
        'MyApp',
        # Rows...
    )
    app.style.theme_use('aqua') # Or whatever theme you're using
    app.mainloop()
    

    The aqua theme is used in the above screenshots but may not be available on all systems.

    You can use the theme viewer example to see the themes available on your system and then set one as above.

    img

  2. Module Documentation

    An attempt has been made to make the ticklish_ui module documentation as comprehensive as possible. It can be viewed in a number of ways.

    With pydoc from the commandline:

    pydoc3 ticklish_ui.widgets.application
    

    With help() from the python interactive interpreter:

    >>> import ticklish_ui
    >>> help(ticklish_ui.events.EventStream)
    

    Or just by browsing the source code on github.

    The github repository also includes a number of examples.

  3. Tutorial

    A more in-depth example implementing a simple application for drawing graphs can be found here.

Features

Widgets

The following widgets are currently implemented. Widgets which are marked as ticklish_ui additions are not part of the standard tkinter/tkinter.ttk widgets sets and may have additional attributes and behaviours in addition to those provided by the base widget.

`ticklish_ui` name Base widget `ticklish_ui` addition
Application tkinter.Tk yes
Button tkinter.ttk.Button no
Canvas tkinter.Canvas no
CheckGroup tkinter.ttk.Frame yes
Checkbutton tkinter.ttk.Checkbutton no
CloseButton tkinter.ttk.Button yes
Combobox tkinter.ttk.Combobox no
Dropdown tkinter.ttk.Combobox yes\*
Entry tkinter.ttk.Entry no
Frame tkinter.ttk.Frame no
Label tkinter.ttk.Label no
LabelFrame tkinter.ttk.LabelFrame no
Listbox tkinter.ttk.Treeview yes\*
RadioGroup tkinter.ttk.Frame yes
Radiobutton tkinter.ttk.Radiobutton no
Toplevel tkinter.Toplevel no

*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.

Streams

Ticklish 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: 10

Note that, although data is being inserted into the base stream, it's the child streams — odd_stream and even_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 Development

On the todo list in no particular order:

  • Allow merging streams
  • Implement the rest of the tkinter and tkinter.ttk widgets
  • Add a way to declaratively define grid layouts

Contributing

For detailed information on contributing to ticklish_ui see CONTRIBUTING.org on github.

License

ticklish_ui is free software licensed under the BSD-3-Clause License.

Release files for ticklish-ui 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ticklish-ui 0.2.0
File Size Uploaded
ticklish_ui-0.2.0.tar.gz 21.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ticklish-ui 0.2.0
File Interpreter ABI Platform
ticklish_ui-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 63.0 kB

Release files / ticklish_ui-0.2.0.tar.gz

Download URL ticklish_ui-0.2.0.tar.gz
Size 21.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d5f37a6dea9241bb3b9c9501d85d4595cf6beb30958d136a5885d597821713cd
BLAKE2b-256 checksum
How to use checksums
2d263482083ef67d37524eae368caaa2c7fc5c694f3ec2428073647a545a1914
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/52.0.0 requests-toolbelt/0.9.1 tqdm/4.58.0 CPython/3.8.2

Release files / ticklish_ui-0.2.0-py3-none-any.whl

Download URL ticklish_ui-0.2.0-py3-none-any.whl
Size 41.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ae523dc9254fc7949b55bee01de529ca284c2087db8062599291506a32c985c3
BLAKE2b-256 checksum
How to use checksums
f6b85e72204270dc3a448afeaf84f6dbd2dc1ae0b6c4dffa6d657a8913bef3af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/52.0.0 requests-toolbelt/0.9.1 tqdm/4.58.0 CPython/3.8.2

Release history Release notifications | RSS feed

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page