Skip to main content

"PUI" Python Declarative UI Framework

Project description

What is PUI

PUI is a reactive/declarative UI framework with two-way data binding. PUI doesn't do UI itself, it turns imperative UI libraries into reactive/declarative flavor with virtual DOM and aims to maintain interoperability.

Slides for SciWork 2023

CPPUI: Experimental C++ Version

Installation

pip install QPUIQ

# Optional, for hot-reload
pip install jurigged

# Optional, for PySide6 backend
pip install PySide6

# Optional, for textual backend
pip install textual

# Optional, for wxPython backend
pip install wxPython

# Optional, for flet backend
pip install flet

Get Started

Hello World

# example/hello_world.py
from PUI.PySide6 import *

@PUIApp
def Example():
    with Window(title="test", size=(320,240)):
        Label("Hello world")

root = Example()
root.run()

Hello World

State & Data Binding

# example/generic_textfield.py
from PUI.PySide6 import *

data = State()
class Example(Application):
    def __init__(self):
        super().__init__()
        data.var = 0

    def content(self):
        with Window(title="blah"):
            with VBox():
                with HBox():
                    Button("-").click(self.on_minus)
                    Label(f"{data.var}")
                    Button("+").click(self.on_plus)

                TextField(data("var")) # binding

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

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

root = Example()
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/generic_canvas.py

from PUI.PySide6 import *

data = State()
class Example(Application):
    def __init__(self):
        super().__init__()
        data.var = 50

    def content(self):
        with Window(title="blah", size=(640,480)):
            with VBox():
                Canvas(self.painter, data.var)
                with HBox():
                    Button("-").click(self.on_minus)
                    Label(f"{data.var}").layout(weight=1)
                    Button("+").click(self.on_plus)

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

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

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

root = Example()
root.run()

Canvas

Cookbook

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

Cookbook 1 Cookbook 2

python -m cookbook textual Cookbook textual

python -m cookbook flet Cookbook flet

python -m cookbook tkinter Cookbook tkinter

Hot Reload

pip install jurigged

Then PUI will take care of view update (code)

Backends

Tier-1

  • PySide6

Lower Priority

Documents

Used by

TODO

  • Dump with layout parameters and add test cases
  • Toga
  • [ISSUE] flet layout sizing (cookbook scroll example)
  • nested state trigger
    • set state in PUIView init
    • set state in setup() ?
  • Tabs(tabposition)
  • Lazy List
  • UI Flow
    • Navigation Stack
    • View Router
    • Model Window/Dialog
  • Layout
    • SwiftUI style overlay ??
  • Canvas
    • Arc
    • ...
  • State with Pydantic support?

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.33.tar.gz (49.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qpuiq-0.33-py3-none-any.whl (76.2 kB view details)

Uploaded Python 3

File details

Details for the file qpuiq-0.33.tar.gz.

File metadata

  • Download URL: qpuiq-0.33.tar.gz
  • Upload date:
  • Size: 49.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for qpuiq-0.33.tar.gz
Algorithm Hash digest
SHA256 2889be775088cdceee438a495cd8e369317ea6943689e6688535b9f624f4e702
MD5 e4af692143ae28479bbfc23b2b8641f9
BLAKE2b-256 8058dba0cbdbaeaad77f6ad4f77a50fca9601275d5e75dea762a075be1733a8d

See more details on using hashes here.

File details

Details for the file qpuiq-0.33-py3-none-any.whl.

File metadata

  • Download URL: qpuiq-0.33-py3-none-any.whl
  • Upload date:
  • Size: 76.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for qpuiq-0.33-py3-none-any.whl
Algorithm Hash digest
SHA256 fe40718078df037ef2c4857246efb518969ad0375be3ef42c6213d68cc4d0424
MD5 90e1d8c3a73ed596d9143abce4bf689c
BLAKE2b-256 bb55ce71c5e4d550827fd66c30c11c6d511f76225f8f34d19a68c76a501e6aeb

See more details on using hashes here.

Supported by

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