Skip to main content

"PUI" Python Declarative UI Framework

Project description

What is PUI

PUI is a declarative UI framework with two-way data binding

Installation

pip install QPUIQ

Get Started

Hello World

# example/hello_world.py

from PUI.PySide6 import *

class Example(Application):
    def content(self):
        with Window(title="test", size=(320,240)):
            Label("Hello world")

root = Example()
root.run()

Hello World

State & Data Binding

# example/pyside6_textfield.py

from PUI.PySide6 import *

data = State()
data.var = 0

class QtExample(QtApplication):
    def content(self):
        with QtWindow(title="blah"):
            with QtVBox():
                with QtHBox():
                    QtButton("-", self.on_minus)
                    QtLabel(f"{data.var}")
                    QtButton("+", self.on_plus)

                QtLineEdit(data("var")) # binding

    def on_minus(self):
        data.var -= 1

    def on_plus(self):
        data.var += 1

root = QtExample()
root.run()

State & Data Binding

View Component

# example/bleak_list.py

....

@PUI # View Component
def DeviceView(device, advertising_data):
    Label(f"{device.address} {device.name} {advertising_data.rssi}")

class GUI(Application):
    def __init__(self, state):
        super().__init__()
        self.state = state

    def content(self):
        with Window(title="BLE List"):
            with VBox():
                Label(f"Found {len(self.state.scanned_devices)} devices")
                for device, advertising_data in self.state.scanned_devices:
                    DeviceView(device, advertising_data)

....

View Component

Layout & Styling

# example/pyside6_feedparser.py

...
with VBox():
    Label(title).qt(StyleSheet={"font-weight":"bold"}) # QT-specific

    with HBox():
        with Scroll():
            with VBox():
                for i,e in enumerate(entries):
                    Label(e.title).click(self.entry_selected, i)
                Spacer()

        with Scroll().layout(weight=1): # Generic Layout Parameter
            if 0 <= selected and selected < len(entries):
                (Text(entries[selected].description)
                    .layout(padding=10) # Generic Layout Parameter
                    .qt(StyleSheet="background-color:white; color:black")) # QT-specific
...

Layout & Styling

Canvas

# example/pyside6_canvas.py

from PUI.PySide6 import *

data = State()
data.var = 50

class QtExample(QtApplication):
    def content(self):
        with QtWindow(title="blah", size=(640,480)):
            with QtVBox():
                QtCanvas(self.painter, data.var)
                with QtHBox():
                    QtButton("-", self.on_minus)
                    QtLabel(f"{data.var}")
                    QtButton("+", self.on_plus)

    @staticmethod
    def painter(canvas, var):
        canvas.drawText(var, var/2, f"blah {var}")
        canvas.drawLine(var, var, var*2, var*3)

    def on_minus(self):
        data.var -= 1

    def on_plus(self):
        data.var += 1

root = QtExample()
root.run()

Canvas

Cookbook

python -m cookbook PySide6 (requires pygments for syntax highlight)

Cookbook 1 Cookbook 2

python -m cookbook textual Cookbook textual

Hot-Reload with Reloadium

Hot-Reload with Reloadium

Backends

Tier-1

  • PySide6

Lower Priority

Generic Expression

Elements

  • HBox()
  • VBox()
  • Spacer()
  • Button(text)
    • .click(callback, *cb_args, **cb_kwargs)
  • Label(text)
    • .click(callback, *cb_args, **cb_kwargs)
  • TextField(binding)
  • ProgressBar(progress 0-1)
  • Scroll()
  • Canvas
    • .drawText(x, y, text)
    • .drawLine(x1, y1, x2, y2, color=0xFF0000, width=2)
    • .drawPolyline([x1, y2, ..., xn, yn], color=0xFF0000, width=2)

Layout

  • .layout(width=320, height=240, weight=1)

Hot Reload

Add these lines to your view file and run with reloadium

import reloadium

# reloadium: after_reload
def after_reload(actions):
    PUIView.reload()

TODO

  • Use threading.locals() instead of inspect
  • State
    • Update Trigger
    • Binding
    • StateList
    • StateDict
    • Lazy UI?
  • StateObject decorator
  • Adapters
    • Split Application/Window, multi-windows
    • UI Flow
      • Navigation Stack
      • View Router
      • Model Window/Dialog
    • Label
    • Button
    • TextField
    • TimelimeView
    • Layout
      • HBox
      • VBox
      • ZBox
      • Grid
        • Row
        • Column
      • SwiftUI style overlay ??
    • Canvas
      • Text
      • Line
      • Rect
      • Arc
      • Image
      • ...
    • Table
    • Tree
    • Scrollbar (or as a layout setting)
  • Better DOM syncer
    • Prevent unnecessary nested update
    • Trace Event Source (TextField) and prevent update it DOM Sync
  • Pydantic State

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

QPUIQ-0.2.2.tar.gz (23.6 kB view details)

Uploaded Source

Built Distribution

QPUIQ-0.2.2-py3-none-any.whl (38.3 kB view details)

Uploaded Python 3

File details

Details for the file QPUIQ-0.2.2.tar.gz.

File metadata

  • Download URL: QPUIQ-0.2.2.tar.gz
  • Upload date:
  • Size: 23.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.3

File hashes

Hashes for QPUIQ-0.2.2.tar.gz
Algorithm Hash digest
SHA256 133ff3849bd6aee4e38f523dedeeeb99dbd549e9bb435ef13a9db6eec91816aa
MD5 953e0c589a0eda5ba035aee539c66ea0
BLAKE2b-256 09187d24eec03849560bb43ed1c8eafc8a77ec23c5e5f07967ef72d295a6466f

See more details on using hashes here.

File details

Details for the file QPUIQ-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: QPUIQ-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 38.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.3

File hashes

Hashes for QPUIQ-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 4dc9f8cdf1c18f92053d131a37bad65c2ed99bff36154e23a1eb49e06e6d045c
MD5 0cb0b264dc4c6fd02c6fe63bbf9303d0
BLAKE2b-256 2ef9d2d1835757303426e5138153816214169bdfe3025a51380db32284d66061

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page