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/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 with Reloadium

Hot-Reload with Reloadium

Backends

Tier-1

  • PySide6

Lower Priority

Declarative Components

Generic PySide6 flet tkinter textual
Application QApplication Page Tk App
Window QMainWindow ✓(Single) Toplevel ✓(Single)
HBox QHBoxLayout Row Frame(grid) Horizontal
VBox QVBoxLayout Column Frame(grid) Vertical
Spacer QSpacerItem
Label QLabel Text Label Label/Button
Button QPushButton ElevatedButton Button Button
Checkbox QCheckBox Checkbox Checkbutton Checkbox
RadioButton QRadioButton Radio Radiobutton RadioButton
Canvas ✓(QWidget) Canvas Canvas -
TextField QLineEdit TextField Entry Input
ProgressBar QProgressBar ProgressBar Progressbar ProgressBar
Scroll QScrollArea ScrollableContainer
Text QLabel Text Label Text
Html QLabel ⚠ Text ⚠ Label ⚠ Text
MarkDown QLabel Markdown ⚠ Label Markdown
Combobox QComboBox - - -
ComboboxItem - - -
Tabs QTabWidget Tabs Notebook Tabs
Tab Tab
MenuBar QMenuBar - - -
Menu QMenu - - -
MenuAction QAction - - -
MdiArea QMdiArea - - -
MdiSubWindow QMdiSubWindow - - -
Splitter QSplitter - - -
Modal ✓(QWidget) - - -
(Wrapper) QtWrapper - - -

Imperative Dialogs

Generic PySide6 flet tkinter textual
OpenDirectory QFileDialog.getExistingDirectory - - -
OpenFile QFileDialog.getOpenFileName - - -
OpenFiles QFileDialog.getOpenFileNames - - -
SaveFile QFileDialog.getSaveFileName - - -
Information QMessageBox - - -
Warning QMessageBox - - -
Critical QMessageBox - - -
Confirm QMessageBox - - -
Prompt QInputDialog - - -

Interfaces

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

Modifiers

  • .layout(width=320, height=240, weight=1, padding=, margin=)
  • .style(color=0xFF0000, bgColor=0x0, fontSize=16, fontWeight="bold", fontFamily="Arial")
  • .qt(HorizontalPolicy=, VerticalPolicy=, SizeConstraint=, StyleSheet={})
  • .flet(k=v)

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

  • [ISSUE] empty virtual node
  • [ISSUE] textual layout sizing (cookbook scroll example)
  • [ISSUE] flet layout sizing (cookbook scroll example)
  • nested state trigger
    • set state in PUIView init
    • set state in setup() ?
  • Tabs(tabposition)
  • Lazy List
  • StateObject decorator
  • UI Flow
    • Navigation Stack
    • View Router
    • Model Window/Dialog
  • Layout
    • ZBox
    • Grid
      • Row
      • Column
    • SwiftUI style overlay ??
  • Canvas
    • Rect
    • Arc
    • Image
    • ...
  • Table
  • Tree
  • Dialog
  • 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.2.5.tar.gz (30.6 kB view details)

Uploaded Source

Built Distribution

QPUIQ-0.2.5-py3-none-any.whl (48.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for QPUIQ-0.2.5.tar.gz
Algorithm Hash digest
SHA256 1fa6aeadec99e9317c4984494d9ecd932941c7ce03aea18772922ef0f2bbd5cc
MD5 730da36729fcf7e04943c343cd5f4b47
BLAKE2b-256 6070658e383cf58e23d19fd50f63fbfcfda06e170d71d83d71eaea3dbc42d49d

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for QPUIQ-0.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 36aea2a5e03fc03c1482734b54de6473412543742608c9e0ce33c86689246b13
MD5 c7187a352637c37d672a2df9a68e896c
BLAKE2b-256 cf9736b6ab88d7a1b77271e8595b96cb1bd973634cd544a95bf256a94ad07d0d

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