Skip to main content

Tasty way to build Qt apps

Project description

QtPie

Tasty way to build Qt apps

from qtpie import entrypoint, make, state, widget
from qtpy.QtWidgets import QLabel, QPushButton, QWidget


@entrypoint
@widget
class Counter(QWidget):
    count: int = state(0)
    label: QLabel = make(QLabel, bind="Count: {count}")
    button: QPushButton = make(QPushButton, "+1", clicked="increment")

    def increment(self) -> None:
        self.count += 1

Click the button. State changes. Label updates. That's it.

Declarative. Reactive. Delightful.

Install

pip install qtpie

Features

  • state() - reactive variables that update the UI
  • bind="{x}" - format expressions with auto-refresh
  • clicked="method" - signal connections by name
  • @widget - dataclass-style components with automatic layouts
  • Widget[T] - type-safe model binding
  • SCSS hot reload - style with CSS classes
  • Async support - async def just works
  • pyright strict - full type safety, no compromises

Why QtPie?

Qt is powerful but verbose:

# Plain Qt - 35 lines of boilerplate
class Counter(QWidget):
    def __init__(self):
        super().__init__()
        self.setObjectName("Counter")
        self.count = 0

        layout = QVBoxLayout(self)

        self.label = QLabel("Count: 0")
        self.label.setObjectName("label")
        layout.addWidget(self.label)

        self.button = QPushButton("Add")
        self.button.setObjectName("button")
        self.button.clicked.connect(self.increment)
        layout.addWidget(self.button)

    def increment(self):
        self.count += 1
        self.label.setText(f"Count: {self.count}")


if __name__ == "__main__":
    app = QApplication([])
    window = Counter()
    window.show()
    app.exec()

vs QtPie - 12 lines, fully reactive:

@entrypoint
@widget
class Counter(QWidget):
    count: int = state(0)
    label: QLabel = make(QLabel, bind="Count: {count}")
    button: QPushButton = make(QPushButton, "+1", clicked="increment")

    def increment(self) -> None:
        self.count += 1

Quick Examples

Reactive State

count: int = state(0)
label: QLabel = make(QLabel, bind="Count: {count}")

self.count += 1  # Label updates instantly

Two-Way Binding

@widget
class Greeter(QWidget):
    name: str = state("")
    name_input: QLineEdit = make(QLineEdit, bind="name")
    greeting: QLabel = make(QLabel, bind="Hello, {name}!")

Type in the input, greeting updates. Change self.name, input updates.

Format Expressions

bind="Count: {count}"
bind="{first} {last}"
bind="{name.upper()}"
bind="Total: ${price * 1.1:.2f}"

Automatic Layouts

@widget
class MyWidget(QWidget):
    top: QLabel = make(QLabel, "Top")
    middle: QLabel = make(QLabel, "Middle")
    bottom: QLabel = make(QLabel, "Bottom")

@widget(layout="form")
class MyForm(QWidget):
    name: QLineEdit = make(QLineEdit, form_label="Name:")
    email: QLineEdit = make(QLineEdit, form_label="Email:")

Model Binding

@dataclass
class Person:
    name: str = ""
    age: int = 0

@widget
class PersonEditor(QWidget, Widget[Person]):
    name: QLineEdit = make(QLineEdit)  # auto-binds to model.name
    age: QSpinBox = make(QSpinBox)      # auto-binds to model.age

Full Qt Access

QtPie is a layer, not a cage. All of Qt is still there:

@widget
class MyWidget(QWidget):
    label: QLabel = make(QLabel, "Hello")

    def setup(self) -> None:
        self.setWindowTitle("My App")
        self.label.setStyleSheet("color: red;")

Documentation

https://mrowrlib.github.io/qtpie

License

0BSD

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

qtpie-0.1.9.tar.gz (47.8 kB view details)

Uploaded Source

Built Distribution

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

qtpie-0.1.9-py3-none-any.whl (65.7 kB view details)

Uploaded Python 3

File details

Details for the file qtpie-0.1.9.tar.gz.

File metadata

  • Download URL: qtpie-0.1.9.tar.gz
  • Upload date:
  • Size: 47.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for qtpie-0.1.9.tar.gz
Algorithm Hash digest
SHA256 d8886771bd2092de0b415ffe5c23c1894d2465a6c03248a00c37e0244b17d42b
MD5 3dd6796c8b847d1446a455b3976c8fa2
BLAKE2b-256 88177595508349aa3cee10fd79330d69c8eb65eda20cb48ef87fc7d5c8b49c6f

See more details on using hashes here.

File details

Details for the file qtpie-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: qtpie-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 65.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for qtpie-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 0e083a0b45ccfaea2c99051fcacb64c844ba16939b8be91570dd551f03a1fb1a
MD5 eb35aa7ce5efd8e19e34506ad1b6774e
BLAKE2b-256 6a67e6b7ef408cfe619f377f79490a1a4b33b99f951d3cf42959fb5aee3bb995

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