pyside6-qml-views

All UI in this architecture is defined declaratively in .qml files. QML views bind to Python bridge properties and call bridge slots — they contain no business logic.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "pyside6-qml-views" with this command: npx skills add ds-codi/project-memory-mcp/ds-codi-project-memory-mcp-pyside6-qml-views

PySide6 QML Views

All UI in this architecture is defined declaratively in .qml files. QML views bind to Python bridge properties and call bridge slots — they contain no business logic.

QML File Organization

resources/ ├── qml/ │ ├── main.qml # Root window / StackLayout host │ ├── components/ │ │ ├── ActionButton.qml # Reusable styled button │ │ ├── StatusBadge.qml # Status indicator │ │ ├── SearchBar.qml # Search input with debounce │ │ ├── LoadingOverlay.qml # Busy spinner overlay │ │ └── ErrorBanner.qml # Error message bar │ ├── pages/ │ │ ├── JobListPage.qml # Job listing with cards │ │ ├── JobDetailPage.qml # Single job detail view │ │ ├── SettingsPage.qml # App settings form │ │ └── DashboardPage.qml # Overview / landing page │ ├── dialogs/ │ │ ├── CreateJobDialog.qml # Modal dialog for new job │ │ └── ConfirmDialog.qml # Generic confirmation popup │ └── styles/ │ ├── Theme.qml # Colour palette, spacing, fonts │ └── qmldir # Module metadata for imports ├── icons/ │ ├── *.svg # Vector icons │ └── *.png # Raster icons └── qml.qrc # Qt resource file (optional)

Root Window (main.qml)

import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15

ApplicationWindow { id: root visible: true width: 1280 height: 720 title: "My Application"

// Page navigation
StackLayout {
    id: pageStack
    anchors.fill: parent
    currentIndex: 0

    JobListPage {}
    JobDetailPage {}
    SettingsPage {}
}

// Global toolbar
header: ToolBar {
    RowLayout {
        anchors.fill: parent

        Label {
            text: "My App"
            font.bold: true
            Layout.leftMargin: 12
        }

        Item { Layout.fillWidth: true }

        ToolButton {
            text: "Jobs"
            onClicked: pageStack.currentIndex = 0
        }
        ToolButton {
            text: "Settings"
            onClicked: pageStack.currentIndex = 2
        }
    }
}

// Global error banner
ErrorBanner {
    id: errorBanner
    anchors { top: parent.top; left: parent.left; right: parent.right }
    visible: jobBridge.errorMessage !== ""
    message: jobBridge.errorMessage
}

// Loading overlay
LoadingOverlay {
    anchors.fill: parent
    visible: jobBridge.isBusy
}

}

Page Pattern

Every page is a self-contained QML file that binds to bridge properties:

// pages/JobListPage.qml import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15

Page { id: jobListPage

header: ToolBar {
    RowLayout {
        anchors.fill: parent
        SearchBar {
            id: searchBar
            Layout.fillWidth: true
            onSearchTriggered: jobBridge.searchJobs(query)
        }
        ActionButton {
            text: "New Job"
            icon.name: "add"
            onClicked: createJobDialog.open()
        }
    }
}

ListView {
    id: jobsListView
    anchors.fill: parent
    model: jobListModel
    spacing: 4
    clip: true

    delegate: ItemDelegate {
        width: jobsListView.width
        height: 64

        contentItem: RowLayout {
            spacing: 12
            Label {
                text: model.jobNumber
                font.bold: true
                Layout.preferredWidth: 100
            }
            Label {
                text: model.jobName
                Layout.fillWidth: true
                elide: Text.ElideRight
            }
            StatusBadge {
                status: model.status
            }
        }

        onClicked: {
            jobBridge.activateJob(model.jobNumber)
            pageStack.currentIndex = 1  // navigate to detail
        }
    }

    // Empty state
    Label {
        anchors.centerIn: parent
        visible: jobsListView.count === 0
        text: "No jobs found"
        opacity: 0.5
    }
}

CreateJobDialog {
    id: createJobDialog
}

}

Reusable Component Pattern

Component File Structure

// components/ActionButton.qml import QtQuick 2.15 import QtQuick.Controls 2.15

Button { id: control

// Custom properties
property color accentColor: "#1976D2"
property bool loading: false

enabled: !loading
opacity: enabled ? 1.0 : 0.5

contentItem: Row {
    spacing: 8
    BusyIndicator {
        running: control.loading
        visible: control.loading
        width: 16; height: 16
    }
    Label {
        text: control.text
        color: "white"
        verticalAlignment: Text.AlignVCenter
    }
}

background: Rectangle {
    radius: 4
    color: control.down ? Qt.darker(accentColor, 1.2)
         : control.hovered ? Qt.lighter(accentColor, 1.1)
         : accentColor
}

}

Component with Custom Signals

// components/SearchBar.qml import QtQuick 2.15 import QtQuick.Controls 2.15

TextField { id: searchField

signal searchTriggered(string query)

placeholderText: "Search..."
selectByMouse: true

// Debounced search
Timer {
    id: debounceTimer
    interval: 300
    onTriggered: searchField.searchTriggered(searchField.text)
}

onTextChanged: debounceTimer.restart()
onAccepted: {
    debounceTimer.stop()
    searchTriggered(text)
}

}

Dialog Pattern

// dialogs/CreateJobDialog.qml import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15

Dialog { id: dialog title: "Create New Job" modal: true anchors.centerIn: Overlay.overlay width: 400 standardButtons: Dialog.Ok | Dialog.Cancel

onAccepted: {
    if (jobNumberInput.text.trim() !== "") {
        jobBridge.createJob(jobNumberInput.text.trim())
    }
}
onRejected: dialog.close()

// Reset on open
onOpened: {
    jobNumberInput.text = ""
    jobNumberInput.forceActiveFocus()
}

ColumnLayout {
    anchors.fill: parent
    spacing: 12

    Label { text: "Job Number" }
    TextField {
        id: jobNumberInput
        Layout.fillWidth: true
        placeholderText: "e.g. 1234567"
        validator: RegularExpressionValidator {
            regularExpression: /^\d{5,8}[A-Z]?$/
        }
    }

    Label {
        text: "Enter a valid job number (5-8 digits, optional letter suffix)"
        font.pixelSize: 11
        opacity: 0.6
    }
}

}

Theme / Styling

Theme Singleton

// styles/Theme.qml pragma Singleton import QtQuick 2.15

QtObject { // Colours readonly property color primary: "#1976D2" readonly property color primaryDark: "#1565C0" readonly property color accent: "#FF9800" readonly property color background: "#FAFAFA" readonly property color surface: "#FFFFFF" readonly property color error: "#D32F2F" readonly property color textPrimary: "#212121" readonly property color textSecondary: "#757575"

// Spacing
readonly property int spacingSmall: 4
readonly property int spacingMedium: 8
readonly property int spacingLarge: 16
readonly property int spacingXLarge: 24

// Typography
readonly property int fontSizeSmall: 12
readonly property int fontSizeMedium: 14
readonly property int fontSizeLarge: 18
readonly property int fontSizeTitle: 24

// Elevation / Radii
readonly property int borderRadius: 4
readonly property int cardRadius: 8

}

qmldir (module registration)

// styles/qmldir module Styles singleton Theme 1.0 Theme.qml

Usage

import "styles" as Styles

Rectangle { color: Styles.Theme.surface radius: Styles.Theme.cardRadius

Label {
    color: Styles.Theme.textPrimary
    font.pixelSize: Styles.Theme.fontSizeMedium
}

}

Loading States

// components/LoadingOverlay.qml import QtQuick 2.15 import QtQuick.Controls 2.15

Rectangle { id: overlay color: "#80000000" // semi-transparent black visible: false z: 999

BusyIndicator {
    anchors.centerIn: parent
    running: overlay.visible
    width: 48; height: 48
}

MouseArea {
    anchors.fill: parent
    // Block clicks through overlay
}

}

Status Indicator

// components/StatusBadge.qml import QtQuick 2.15 import QtQuick.Controls 2.15

Rectangle { id: badge property string status: ""

width: statusLabel.implicitWidth + 16
height: 24
radius: 12
color: {
    switch (status.toLowerCase()) {
        case "active":   return "#4CAF50";
        case "complete": return "#2196F3";
        case "on_hold":  return "#FF9800";
        case "archived": return "#9E9E9E";
        default:         return "#BDBDBD";
    }
}

Label {
    id: statusLabel
    anchors.centerIn: parent
    text: badge.status
    color: "white"
    font.pixelSize: 11
    font.bold: true
}

}

QML Best Practices

Rule Rationale

Keep components under 150 lines Maintainability; extract sub-components

One root item per file QML convention

Use id only when referenced Avoid unnecessary identity

Prefer property bindings over imperative JS Declarative updates, fewer bugs

Use Loader for heavy / conditional content Lazy instantiation saves memory

Never embed SQL, HTTP, or file I/O in QML JS All side-effects go through bridge slots

Qualify property access (root.width vs width ) Avoid shadowing in nested items

Use anchors or layouts, not manual x/y Responsive and maintainable

Resource Loading

Icons from filesystem

Image { source: "file:///" + Qt.resolvedUrl("../../icons/logo.svg") }

Icons via Qt Resource System

Image { source: "qrc:/icons/logo.svg" }

Qt Resource File (qml.qrc)

<RCC> <qresource prefix="/"> <file>qml/main.qml</file> <file>qml/components/ActionButton.qml</file> <file>icons/logo.svg</file> </qresource> </RCC>

References

  • QML Coding Conventions

  • Qt Quick Controls

  • Qt Quick Layouts

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

pyside6-mvc

No summary provided by upstream source.

Repository SourceNeeds Review
General

pyside6-qml-architecture

No summary provided by upstream source.

Repository SourceNeeds Review
General

bugfix

No summary provided by upstream source.

Repository SourceNeeds Review
General

mvc-architecture

No summary provided by upstream source.

Repository SourceNeeds Review