A flexible toolset to improve QML coding experience for PyQt/PySide development.
Project description
LK QtQuick Scaffold
Using Python and QtQuick QML to build desktop applications from a series of predefined tools.
Highlights
- A layout engine to extend QML layouts.
- Integrate Qt logging with python console.
- Execute Python snippet in QML, and vice versa.
- Easy-to-use register handler to register Python functions to QML side.
- Well type-annotated signal and slot (and more elegant writing style!)
- Hot loader to verify layout changing on the fly.
- Stylesheet manager to thoroughly control application appearance (color, size, motion, typography, and so on).
- A set of built-in widgets/themes to quickly produce beautiful user interface.
How to install
lk-qtquick-scaffold
requires Python 3.8+ interpreter version.
Use pip install:
# the 1.x version. (1.3.0)
pip install lk-qtquick-scaffold
# the next big version is coming soon. currently i've released a preview version.
pip install lk-qtquick-scaffold>=2.0.0a0
Note: many features in this document are based on 2.0, currently the 2.0 formal release is still in progress, you may install the alpha version to taste the newest features.
Install Qt backend
Installing lk-qtquick-scaffold doesn't include Python for Qt's library. You need to manually install one of the follows:
# choose one to install
pip install pyside6
pip install pyqt6
pip install pyside2
pip install pyqt5
lk-qtquick-scaffold auto detects the Qt backend you've installed (you can also explicitly set the specific one), it uses qtpy to provide an uniform layer overrides PySide6/PyQt6/PySide2/PyQt5.
Examples quick through
Hello world
view.qml
import QtQuick
import QtQuick.Window
Window {
visible: true
width: 400
height: 300
Text {
anchors.centerIn: parent
text: 'Hello world!'
}
}
main.py
from lk_qtquick_scaffold import app
app.run('view.qml')
Hot loader
The app.run
method accepts debug
(bool type) parameter, to enable hot
loader mode:
from lk_qtquick_scaffold import app
app.run('view.qml', debug=True)
It starts a floating window that includes a button "RELOAD", each time when you modify "view.qml", click "RELOAD" to refresh your GUI:
BTW you can run "view.qml" in command line:
# see help
py -m lk_qtquick_scaffold -h
# run
py -m lk_qtquick_scaffold run view.qml
# run in debug mode
py -m lk_qtquick_scaffold run view.qml --debug
It has the same result like above "main.py" does.
Register funtions to QML
from lk_qtquick_scaffold import QObject, app, pyside, slot
class MyObject(QObject):
@slot(result=str)
def hello(self):
return 'hello world'
# 1. register QObject subclasses by `app.register`
app.register(MyObject())
# it will be available as 'MyObject' in QML side.
# 1.1. or use alias
app.register(MyObject(), name='PyObject')
# it will be available as 'PyObject' in QML side.
# 2. register regular function by `pyside.register`.
def foo(a: int, b: int, c: int):
return a + b + c
pyside.register(foo)
# it will be available as 'pyside.call("foo", ...)' in QML side.
# 2.1. or use alias
pyside.register(foo, name='add_abc')
# it will be available as 'pyside.call("add_abc", ...)' in QML side.
view.qml
import QtQuick
Item {
Component.onCompleted: {
console.log(MyObject.hello()) // -> 'hello world'
console.log(PyObject.hello()) // -> 'hello world'
console.log(pyside.call("foo", [1, 2, 3])) // -> 6
console.log(pyside.call("add_abc", [1, 2, 3])) // -> 6
}
}
Integrate qt logging in python console
When you use console.log
in QML side, it will be printed in Python console:
Signal and Slot
The signal
and slot
wrap on Qt's Signal
and Slot
decorators, but
extended their functionalities:
-
You can get the correct type hint in IDE:
-
The
slot
accepts more types as alias to "QObject" and "QVariant" -- it is more convenient and more readable:from lk_qtquick_scaffold import QObject, slot class MyObject(QObject): @slot(int, dict, result=list) # <- here def foo(self, index, data): return [index, len(data)] ''' it is more readable than: @Slot(int, QJSValue, result='QVariant') def foo(self, index, data): return [index, len(data)] '''
Here is a full alias list (which is documented in
lk_qtquick_scaffold/qt_core/signal_slot.py
):slot(*args)
Alias Real value Note bool
bool
basic type float
float
basic type int
int
basic type str
str
basic type QObject
QObject
object object
QObject
object 'item'
QObject
object (string) 'object'
QObject
object (string) 'qobject'
QObject
object (string) dict
QJSValue
qjsvalue list
QJSValue
qjsvalue set
QJSValue
qjsvalue tuple
QJSValue
qjsvalue ...
QJSValue
qjsvalue 'any'
QJSValue
qjsvalue (string) slot(result=...)
Alias Real value Note None
None
basic type bool
bool
basic type float
float
basic type int
int
basic type str
str
basic type dict
'QVariant'
qvariant list
'QVariant'
qvariant set
'QVariant'
qvariant tuple
'QVariant'
qvariant ...
'QVariant'
qvariant -
slot
decorator is non-intrusive -- it means the method been decorated can be called in Python side as usual.from lk_qtquick_scaffold import QObject, slot class MyObject(QObject): @slot(int, str, result=list) def foo(self, index, name): return [index, name] my_obj = MyObject() # you can call it like a regular method! (just 'ignore' its docorator.) my_obj.foo(1, 'hello') # -> [1, 'hello']
Built-in widgets library
lk-qtquick-scaffold
provides a set of built-in widgets under its ~/widgets
directory.
Basically, you can use it in QML by importing "LKWidgets" (or "LKWidgets 1.0" for Qt 5.x):
import LKWidgets
LKWindow {
color: '#DBDBF7' // moon white
LKRectangle {
anchors.fill: parent
anchors.margins: 32
color: '#ECDEC8' // parchment yellow
LKColumn {
anchors.centerIn: parent
alignment: 'hcenter' // horizontally center children
LKGhostButton {
text: 'SUNDAY'
}
LKButton {
text: 'MONDAY'
}
LKGhostButton {
text: 'TUESDAY'
}
LKButton {
text: 'WEDNESDAY'
}
LKGhostButton {
text: 'THURSDAY'
}
LKButton {
text: 'FRIDAY'
}
LKGhostButton {
text: 'SATURDAY'
}
}
}
}
The dark theme:
More screenshots: see examples/lk_widgets/screenshot_*
.
All widget names are started with 'LK', the full list is in
lk_qtquick_scaffold/widgets/LKWidgets/qmldir
file.
Note: the widgets documentation is not ready. Currently you may have a look at
the examples/lk_widgets
screenshots, or view its source code for more details.
High-level model, human-readable API
TODO
Layout engine
Layout engine is powered by lk_qtquick_scaffold.qmlside.layout_helper
, which
is registered as pylayout
in QML side.
// some_view.qml
import QtQuick
Column {
height: 100
Item { id: item1; height: 20 }
Item { id: item2; height: 0.4 }
Item { id: item3; height: 0 }
Item { id: item4; height: 0 }
Component.onCompleted: {
// horizontally center children
pylayout.auto_align(this, 'hcenter')
// auto size children:
// width > 1: as pixels
// width > 0 and < 1: as percent of left spared space
// width = 0: as stretch to fill the left spared space
pylayout.auto_size_children(this, 'vertical')
// the result is:
// item1: 20px
// item2: (100 - 20) * 0.4 = 32px
// item3: (100 - 20 - 32) * 0.5 = 24px
// item4: (100 - 20 - 32) * 0.5 = 24px
// (item 3 and 4 share the left space equally.)
}
}
Executing Python snippet in QML, and vice versa
test.py
from lk_qtquick_scaffold import eval_js
def foo(item1: QObject, item2: QObject):
eval_js('''
$a.widthChanged.connect(() => {
$b.width = $a.width * 2
})
''', {'a': item1, 'b': item2})
view.qml
import QtQuick
ListView {
model: pyside.eval(`
import os
files = os.listdir(input('target folder: '))
return files
`)
}
Style manager
lk-qtquick-scaffold
exposes a list of built-in style controlers to QML side
as follows:
Style | Description |
---|---|
pycolor |
All color specifications defined in a canonical name form |
pyfont |
Font related specifications |
pysize |
Width, height, radius, padding, margin, spacing, etc. |
pymotion |
Animation related specifications (duration, easing type, etc.) |
Usage examples (seen in all LKWidgets):
You can overwrite the style by giving a YAML file to load, for example a "dark-theme.yaml":
# this is dark theme color scheme
# == general ==
blue_1: '#e4e5f8'
blue_3: '#5294eb'
blue_5: '#3844e6'
blue_7: '#0f143b'
dark_1: '#424141'
dark_2: '#242529'
dark_3: '#15141a'
dark_5: '#050408'
grey_3: '#e8eaed'
grey_5: '#a9acb0'
# == widgets spec ==
border_active: '#797171'
border_default: '#575757'
border_glow: '$border_active'
button_bg_active: '$blue_5'
button_bg_default: '$panel_bg'
button_bg_hovered: '$dark_1'
button_bg_pressed: '$dark_3'
button_bg_selected: '$button_bg_pressed'
input_bg_active: '$dark_2'
input_bg_default: '$panel_bg'
input_border_active: '$border_active'
input_border_default: '$border_default'
input_indicator_active: '$blue_5'
panel_bg: '$dark_3'
prog_bg: '$blue_1'
prog_fg: '$blue_5'
sidebar_bg: '$panel_bg'
text_default: '$grey_3'
text_disabled: '$grey_5'
text_hint: '$grey_5'
win_bg_default: '$dark_5'
The dollar symbol ($
) is a simple pointer to the other key.
You don't need to write all colors in the file, lk-qtquick-scaffold
has a
great deduction algorithm to automatically call back "defaults" when required
colors are missing from your sheet.
Finally load it by calling pycolor.update_from_file()
:
from lk_qtquick_scaffold import pycolor
pycolor.update_from_file('dark-theme.yaml')
Warning: currently color name style is under refactoring, it is very unstable to learn from its style.
Gallery
TODO:AddMoreWidgetsDemo
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 Distributions
Built Distribution
File details
Details for the file lk_qtquick_scaffold-2.0.0-py3-none-any.whl
.
File metadata
- Download URL: lk_qtquick_scaffold-2.0.0-py3-none-any.whl
- Upload date:
- Size: 123.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.14 CPython/3.10.5 Darwin/21.2.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8bfb582767002cc86dc24ee26314aa078dad6c3cbe4baab9891529b464d99344 |
|
MD5 | c18765ad0e57a2e95ddac611b555a1af |
|
BLAKE2b-256 | bf55009bf0963fa341241e846b36eefd04f8559b09fafdcc1e1d40649f941259 |