Yet another pythonic UI library using PyQt5
Project description
Qutie
Yet another pythonic UI library for rapid prototyping using PyQt5.
Quick start
import qutie as ui
app = ui.Application()
window = ui.Widget(
title="Example",
icon='orange',
width=320,
height=240,
layout=ui.Column(
ui.Label("Hello world!"),
ui.Row(
ui.Button("Go!", clicked=lambda: ui.show_info(text="Hello world!")),
ui.Button("Quit", clicked=app.quit)
)
)
)
window.show()
app.run()
Documentation
Qutie (pronounced as cutie) provides a simple and easy to use pythonic interface to PyQt5.
Install
pip install qutie
Application
A single Application
object must be created before other widgets. To make use
of the event system the application event loop must be executed.
import qutie as ui
# Create an application object.
app = ui.Application(name='app', version='1.0')
# Create a window.
window = ui.MainWindow()
window.resize(800, 600)
window.show()
# Run the event loop.
app.run()
Widgets
Any widget can be a top level window or part of another widget using the
layout
property. All properties can be assigned using the constructor.
window = ui.Widget(title="Example", width=320, height=240)
To make a top level window visible use property visible
or call method
show()
.
window.show()
window.visible = True # equivalent to show
Layouts
The simplified layout system provides a horizontal Row
and a vertical Column
box. Items can be added while constructing the layout or using list like methods
append
and insert
. The consumed space of every child widget can be adjusted
using the stretch
attribute.
window.layout = ui.Row(
ui.Column(
...
),
ui.Column(
ui.Row(...),
ui.Row(...),
ui.Row(...),
stretch=(1, 0, 0)
),
stretch=(2, 3)
)
Inputs
# Single line text input
text = ui.Text(value="spam")
# Numeric input
number = ui.Number(value=4, minimum=0, maximum=10, step=1.0, decimals=1)
# A multi line text area
textarea = ui.TextArea(value="Lorem ipsum et dolor.")
Events
Events provide a simplified interface to Qt's signal and slot system. Events can
be emitted from any class inheriting from Object
by calling method emit()
.
# Use any callable class attribute as event callback.
window.issue_call = lambda: print("Call to action!")
# Emit an event executing attribute `issue_call` (if callable).
window.emit('issue_call')
Events can also propagate positional and keyword arguments.
# Use any callable class attribute as event callback.
window.update_progress = lambda a, b: print(f"Progress: {a} of {b}")
# Emit an event executing attribute `update_progress` (if callable).
window.emit('update_progress', 42, 100)
Many widgets provide predefined events.
# Assigning callback functions
ui.Number(value=4, changed=on_change, editing_finished=on_edited)
Timers
Call repeating or delayed events using timers.
timer = ui.Timer(interval=1.0, timeout=lambda: print("Done!"))
timer.start()
Function single_shot
exposes a convenient single shot timer.
ui.single_shot(interval=1.0, timeout=lambda: print("Done!"))
Note that timer events are only processed when running the application event loop.
Settings
Persistent settings can be stored/restored using a Settings
object as context
manager. It provides application wide settings as a JSON dictionary.
with ui.Settings() as settings:
value = settings.get('key', 'default')
settings['key'] = value
Use attribute filename
to inspect the persistent JSON data.
>>> ui.Settings().filename
'/home/user/.config/app.qutie'
Menus
Menu bars and menus behave like python lists.
window = ui.MainWindow()
file_menu = window.menubar.append("&File")
quit_action = file_menu.append("&Quit")
quit_action.triggered = window.close
foo_menu = window.menubar.insert(window.menubar.index(file_menu), "&Foo")
file_menu = window.menubar.remove(file_menu)
Toolbars
Toolbars also behave like python lists, the main window toolbars property behaves like a set.
window = ui.MainWindow()
toolbar = window.toolbars.add("toolbar")
toolbar.append(quit_action)
toolbar.insert(quit_action)
window.toolbars.remove(toolbar)
Workers
The Worker
class provides a convenient way to work with background threads.
Use attribute target
to assign the function to be executed in the background.
def calculate(worker):
for i in range(100):
...
worker = ui.Worker(target=calculate)
worker.start()
Important: use only the event system to propagate information from inside the worker. Do not access widgets from within the worker function.
def calculate(worker):
for i in range(100):
# Emit custom events.
worker.emit('progress', i, 100)
worker.emit('message', "All ok...")
worker = ui.Worker(target=calculate)
# Assign custom event callbacks.
worker.progress = lambda step, max: print(f"progress: {step}/{max}")
worker.message = lambda msg: print(f"message: {msg}")
worker.start()
To control worker lifetime use method stop()
and attribute stopping
.
def calculate(worker):
while not worker.stopping:
...
worker = ui.Worker(target=calculate)
worker.start()
...
worker.stop()
To wait for a worker to actually stop use method join()
.
worker.stop()
worker.join()
Example
A simple dialog with progress bar running a calculation in the background.
import random
import time
import qutie as ui
class Dialog(ui.Dialog):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Create worker
self.worker = ui.Worker(target=self.calculate)
self.worker.finished = self.close
self.worker.update_progress = self.update_progress
# Create layout
self.progress_bar = ui.ProgressBar()
self.layout = self.progress_bar
def run(self):
# Start, stop and join worker
self.worker.start()
super().run()
self.worker.stop()
self.worker.join()
def update_progress(self, value, maximum):
self.progress_bar.maximum = maximum
self.progress_bar.value = value
def calculate(self, worker):
n = 32
for i in range(n):
if worker.stopping:
break
# Emit custom event
worker.emit('update_progress', i, n)
time.sleep(random.random())
app = ui.Application()
dialog = Dialog(title="Worker")
dialog.run()
Something missing?
Any underlying PyQt5 instance can be accessed directly using property qt
.
This also enables to mix in custom PyQt5 classes and instances.
widget.qt.setWindowTitle("Spam!")
widget.qt.customContextMenuRequested.connect(lambda pos: None)
widget.qt.layout().addWidget(QtWidgets.QPusbButton())
License
Qutie is licensed under the GNU General Public License Version 3.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file qutie-1.7.0.tar.gz
.
File metadata
- Download URL: qutie-1.7.0.tar.gz
- Upload date:
- Size: 32.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/39.0.1 requests-toolbelt/0.9.1 tqdm/4.57.0 CPython/3.6.9
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 57e86ba014beaea4ff6c3afa5994a235371c942823125988ae9e1cb7c36ac05d |
|
MD5 | 3bad1ad4eabd41f54e0588160eca847a |
|
BLAKE2b-256 | a330141e38e6b838f494fba1dc13abcfa302ece4fa4a70d7f33b11253b31f447 |