UI はローカライズ済みです。スキルの紹介と説明文書は選択した言語へ AI が自動翻訳し、コード・コマンド・パス・専門用語は原文のままです。原作者の文書が優先されます。
スキルを探す
運用・デプロイ · SKILL.md

desktop-qt

desktop-qt

Use when the user asks about cross-platform Qt application development with QtWidgets, QtQuick/QML, Qt Creator, signals and slots, or Qt deployment. Do NOT use for: KDE-specific (desktop-kde), or non-Qt desktop frameworks.

Independent GitHub snapshot · Automated classification · Original documentation governs

スキルの説明

GitHub

name: desktop-qt description: > Use when the user asks about cross-platform Qt application development with QtWidgets, QtQuick/QML, Qt Creator, signals and slots, or Qt deployment. Do NOT use for: KDE-specific (desktop-kde), or non-Qt desktop frameworks. version: "2.0.0" author: "j4flmao" license: "MIT" compatibility: claude-code: true cursor: true codex: true windsurf: true tags: [desktop, qt, cross-platform]

Qt

Purpose

Build cross-platform desktop (and embedded) applications using the Qt framework — QtWidgets for traditional desktop UIs, QtQuick/QML for fluid modern interfaces, with built-in networking, SQL, multimedia, and internationalization.

Agent Protocol

Trigger

Exact user phrases: "Qt", "QtWidgets", "QtQuick", "QML", "QObject", "signals and slots", "QMake", "CMake Qt", "QML application", "Qt Creator", "QML UI", "cross-platform Qt".

Input Context

  • Qt version (Qt5 vs Qt6 — Qt6 for new projects)
  • UI technology (QtWidgets vs QtQuick/QML)
  • Build system (CMake with Qt6, qmake legacy)
  • Platform targets (Windows, macOS, Linux, Android, iOS, embedded)
  • Language (C++ primarily, Python via PySide6)
  • Module requirements (QtCore, QtWidgets, QtQuick, QtNetwork, QtSql, QtMultimedia, QtCharts, QtWebEngine)
  • Performance requirements (real-time rendering, large data models)

Output Artifact

Qt application architecture with widget/QML tree, signal-slot graph, data model, and deployment configuration.

Completion Criteria

  • Qt version and modules selected
  • UI technology chosen (QtWidgets vs QtQuick vs hybrid)
  • Application and main window class hierarchy defined
  • Signal-slot connections mapped for data flow
  • Model-View architecture (QAbstractItemModel, QSortFilterProxyModel)
  • Settings and state persistence (QSettings)
  • Internationalization setup (tr(), .ts/.qm files)
  • Build system configured (CMake with Qt6)
  • Deployment/packaging planned (windeployqt, macdeployqt, linuxdeployqt)
  • Styling approach (Qt stylesheets, QML theming, platform-native look)

Max Response Length

250 lines.

Framework/Methodology

Qt UI Technology Decision Tree

What is the application type?
├── Traditional desktop (forms, dialogs, complex widgets)
│   → QtWidgets — mature, accessible, native look
│   → QMainWindow, QDialog, QFormLayout, QTableView
├── Modern fluid UI (animations, touch, customization)
│   → QtQuick/QML — GPU-accelerated, declarative
│   → QQC2 (Qt Quick Controls 2), animations, shader effects
├── Data-heavy (spreadsheets, financial, scientific)
│   → QtWidgets with QTableView + custom delegates
│   → OR QtQuick with TableView (Qt6) + custom models
├── Embedded (IoT, kiosk, in-vehicle)
│   → QtQuick with Qt Quick Ultralite (for MCUs)
│   └ Or QtWidgets for more complex interaction
└── Hybrid (some QML, some widgets)
    → QWidget::createWindowContainer for embedding QML
    └ QQuickWidget for embedding into QtWidgets

Qt Object Model

QObject (base for all Qt objects)
├── Signals + Slots (type-safe communication)
├── Q_PROPERTY (property system for QML + data binding)
├── Q_INVOKABLE (methods callable from QML)
├── Event system (QEvent, eventFilter, QTimer)
├── QObject hierarchy (parent-child memory management)
└── Meta-object compiler (MOC) for introspection
    ↓
Inherited by:
├── QWidget / QMainWindow / QDialog (QtWidgets)
├── QQuickItem / QQuickWindow (QtQuick)
├── QAbstractItemModel / QAbstractListModel (Model/View)
└── QThread / QObject worker (concurrency)

Workflow

Step 1: Set Up CMake + Qt6 Project

cmake_minimum_required(VERSION 3.16)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

find_package(Qt6 REQUIRED COMPONENTS
    Core Widgets Sql Network Quick QuickControls2
)

add_executable(myapp
    src/main.cpp
    src/mainwindow.cpp src/mainwindow.h
    src/mainwindow.ui
    src/model.cpp src/model.h
    resources.qrc
)

target_link_libraries(myapp PRIVATE
    Qt6::Core Qt6::Widgets Qt6::Sql Qt6::Network
    Qt6::Quick Qt6::QuickControls2
)

# QML module registration
qt_target_qml_sources(myapp
    URI "org.example.myapp"
    VERSION 1.0
    QML_FILES
        qml/Main.qml
        qml/MyComponent.qml
)

Step 2: QtWidgets Application

// main.cpp
#include <QApplication>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QSettings>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    app.setApplicationName("My App");
    app.setOrganizationName("My Org");
    app.setApplicationVersion("1.0.0");

    // Qt6 high-DPI is automatic
    QMainWindow window;
    window.setWindowTitle("My Qt App");
    window.resize(800, 600);

    auto *centralWidget = new QWidget(&window);
    auto *layout = new QVBoxLayout(centralWidget);

    auto *label = new QLabel("Hello, Qt!");
    auto *button = new QPushButton("Click Me");

    // Signal-slot connection
    QObject::connect(button, &QPushButton::clicked, [label]() {
        label->setText("Button clicked!");
    });

    layout->addWidget(label);
    layout->addWidget(button);
    window.setCentralWidget(centralWidget);

    // Restore window geometry
    QSettings settings;
    if (settings.contains("window/geometry")) {
        window.restoreGeometry(settings.value("window/geometry").toByteArray());
    }

    window.show();
    return app.exec();
}

// Save geometry on close (in MainWindow destructor or closeEvent)
void MainWindow::closeEvent(QCloseEvent *event) {
    QSettings settings;
    settings.setValue("window/geometry", saveGeometry());
    QMainWindow::closeEvent(event);
}

Step 3: Model-View Architecture (QtWidgets)

// model.h
#include <QAbstractTableModel>
#include <QVector>
#include <QDateTime>

struct Record {
    int id;
    QString name;
    double value;
    QDateTime timestamp;
};

class MyModel : public QAbstractTableModel {
    Q_OBJECT
public:
    enum Roles {
        IdRole = Qt::UserRole + 1,
        NameRole,
        ValueRole,
        TimestampRole
    };

    explicit MyModel(QObject *parent = nullptr);

    // Required overrides
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const override;

    // Editable model
    Qt::ItemFlags flags(const QModelIndex &index) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    // Data modification
    bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;

    // Sorting support
    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;

private:
    QVector<Record> m_records;
};
// Usage in view
auto *tableView = new QTableView;
auto *model = new MyModel(this);

// Sort proxy for click-to-sort headers
auto *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model);
tableView->setModel(proxyModel);
tableView->setSortingEnabled(true);

// Custom delegate for rendering
tableView->setItemDelegateForColumn(2, new CustomDelegate(this));

Step 4: QtQuick/QML Application

// qml/Main.qml
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.example.myapp 1.0

QQC2.ApplicationWindow {
    id: root
    visible: true
    width: 800
    height: 600
    title: qsTr("My QML App")

    // Header bar
    header: QQC2.ToolBar {
        RowLayout {
            anchors.fill: parent
            QQC2.Label {
                text: qsTr("My App")
                font.pointSize: 14
                font.bold: true
                Layout.leftMargin: 8
            }
            Item { Layout.fillWidth: true }
            QQC2.Button {
                text: qsTr("Settings")
                onClicked: settingsDialog.open()
            }
        }
    }

    // Main content with split layout
    RowLayout {
        anchors.fill: parent
        anchors.margins: 8

        ListView {
            id: listView
            Layout.preferredWidth: 250
            Layout.fillHeight: true
            model: myModel  // C++ model exposed to QML
            delegate: ItemDelegate {
                width: parent.width
                text: model.name
                onClicked: detailView.setData(model)
            }
        }

        // Detail panel
        Loader {
            id: detailView
            Layout.fillWidth: true
            Layout.fillHeight: true
            sourceComponent: detailComponent
        }
    }

    Component {
        id: detailComponent
        ColumnLayout {
            property var currentData: null
            function setData(data) { currentData = data; }

            QQC2.Label { text: qsTr("Name:") + " " + (currentData?.name || "") }
            QQC2.Label { text: qsTr("Value:") + " " + (currentData?.value || "") }
        }
    }
}

Step 5: C++ Model Exposed to QML

// C++ model accessible from QML
#include <QAbstractListModel>

class ItemModel : public QAbstractListModel {
    Q_OBJECT
    QML_ELEMENT  // Qt6: auto-register as QML type
public:
    enum Roles {
        NameRole = Qt::UserRole + 1,
        ValueRole
    };

    int rowCount(const QModelIndex &parent = QModelIndex()) const override {
        return m_items.count();
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
        if (!index.isValid() || index.row() >= m_items.count())
            return {};
        const auto &item = m_items.at(index.row());
        switch (role) {
        case NameRole: return item.name;
        case ValueRole: return item.value;
        default: return {};
        }
    }

    QHash<int, QByteArray> roleNames() const override {
        return {{NameRole, "name"}, {ValueRole, "value"}};
    }

private:
    QVector<ItemData> m_items;
};
// main.cpp (QtQuick version)
QQmlApplicationEngine engine;

// Register C++ types to QML
qmlRegisterType<ItemModel>("org.example.myapp", 1, 0, "ItemModel");

// Or use context property (simpler but less modular)
// engine.rootContext()->setContextProperty("myModel", &model);

engine.loadFromModule("MyApp", "Main");

Step 6: Qt Stylesheets (QtWidgets)

// QSS (Qt Style Sheets) — similar to CSS
app.setStyleSheet(R"(
    QMainWindow {
        background-color: #f5f5f5;
    }
    QPushButton {
        background-color: #3498db;
        color: white;
        border: none;
        padding: 8px 16px;
        border-radius: 4px;
        font-size: 14px;
    }
    QPushButton:hover {
        background-color: #2980b9;
    }
    QPushButton:pressed {
        background-color: #2471a3;
    }
    QPushButton:disabled {
        background-color: #bdc3c7;
    }
    QLineEdit {
        border: 1px solid #bdc3c7;
        border-radius: 4px;
        padding: 6px;
    }
    QTableView {
        gridline-color: #ecf0f1;
        selection-background-color: #3498db;
    }
)");

Common Pitfalls

PitfallDescriptionPrevention
Synchronous I/ONetwork/filesystem on main thread blocks UIUse QNetworkAccessManager, QThread, QtConcurrent
Direct UI from worker threadWidget updates from non-GUI threadUse signals to post to main thread
MOC not regeneratedStale moc_*.cpp after header changesCMAKE_AUTOMOC handles this automatically
Qt5 patterns in Qt6Deprecated APIs removed in Qt6Use Qt6 documentation, clazy checks
QML engine ownership leaksC++ objects created in QML not freedUse parent-child, C++ ownership properly
Ignoring high-DPIBlurry UI on Retina/4K displaysQt6 handles automatically; Qt5: AA_EnableHighDpiScaling
Slow QML startupParsing large QML files, loading assetsLazy loading with Loader, asynchronous image loading
Hardcoded stringsOnly English, no translation supportAlways use qsTr(), tr(), generate .ts files
Missing platform pluginApp won't start on target machineDeploy correct platform DLLs/bundles
QQmlEngine misuseCreating multiple engines or not setting contextSingle engine per application

Best Practices

PracticeRationale
Qt6 for new projectsModern C++17, better QML, removed deprecated APIs
CMake over qmakeQt6 favors CMake, more flexible, cross-platform
Model-View for list dataSeparation of concerns, sort/filter proxy, QML binding
Signals/slots over callbacksType-safe, thread-safe (queued connections), MOC-verified
Q_PROPERTY for QML interopEnables QML data binding, animation, state machine
QSS for styling over QPaletteCSS-like syntax, per-widget customization, easier theming
QRC for embedded resourcesSingle binary, no file path issues, compression
Asynchronous everywhereNetwork, file, database, process — non-blocking
tsan/asan in CICatch data races and memory errors early
Resource files (.qrc)Bundle QML, images, fonts into executable

Architecture Patterns

SQL Data Model

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("app.db");
db.open();

QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("items");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();

QTableView *view = new QTableView;
view->setModel(model);

QtConcurrent for Background Work

QFuture<int> future = QtConcurrent::run([this]() {
    return heavyComputation();
});
auto *watcher = new QFutureWatcher<int>(this);
connect(watcher, &QFutureWatcher<int>::finished, this, [this, watcher]() {
    int result = watcher->result();
    updateUI(result);
});
watcher->setFuture(future);

References

  • references/qt-advanced.md — Qt Advanced Topics
  • references/qt-deployment.md — Qt Deployment Reference
  • references/qt-fundamentals.md — Qt Fundamentals
  • references/qt-qml-patterns.md — Qt QML Architecture Patterns Reference

Handoff

Hand off to desktop-kde for KDE Frameworks integration. Hand off to design-accessibility for Qt accessibility testing.

Implementation Patterns

Observer Pattern for Event Handling

` interface EventObserver { onEvent(event: T): Promise; }

class EventBus { private observers: Set<EventObserver> = new Set(); subscribe(observer: EventObserver): void { this.observers.add(observer); } unsubscribe(observer: EventObserver): void { this.observers.delete(observer); } async emit(event: T): Promise { const results = Array.from(this.observers).map(o => o.onEvent(event)); await Promise.allSettled(results); } } `

Configuration-Driven Approach

config: defaults: timeout: 30s retryCount: 3 overrides: production: timeout: 60s retryCount: 5 development: timeout: 300s retryCount: 1

Production Considerations

Deployment Checklist

  • Configuration validated against schema before startup
  • Health check endpoints registered and monitored
  • Graceful shutdown with draining period (30s timeout)
  • Resource limits configured (CPU, memory, file descriptors)
  • Log level set appropriate for environment
  • Metrics endpoint secured and exposed
  • Rate limiting configured per-tier
  • TLS certificates valid and auto-renewing
  • Database migrations run as separate deployment step
  • Feature flags ready for gradual rollout

Monitoring and Alerting

MetricThresholdSeverityAction
Error rate> 1% over 5minCriticalPage on-call
p99 latency> 2s over 5minWarningInvestigate
Throughput drop> 50% over 1minCriticalCheck upstream
Queue depth> 1000 over 1minWarningScale consumers
Disk usage> 85%WarningClean or expand
Memory usage> 90% heapCriticalRestart or scale

Anti-Patterns

Anti-PatternSymptomRoot CauseSolution
Premature optimizationComplex code for no measured benefitGuessing instead of profilingMeasure first, optimize based on data
Copy-paste reuseDuplicate code across codebaseLack of abstractionExtract shared logic into libraries
Gold-platingFeatures with no current requirementOver-engineeringYAGNI — build what's needed now
Magical thinkingAssumptions without validationSkipping error handlingHandle all failure modes explicitly

Performance Optimization

Caching Strategy

Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge). Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency).

Resource Pooling

  • Database connections: Pool of reusable connections (HikariCP, pgBouncer)
  • HTTP connections: Keep-alive + connection pooling for external calls
  • Thread pool: Bounded thread pools for async task execution

Profiling Methodology

  1. Establish baseline with production traffic profile
  2. Profile CPU with sampling profiler (pprof, perf, async-profiler)
  3. Profile memory with heap dumps and allocation tracking
  4. Profile I/O with strace/perf trace for syscall analysis
  5. Profile latency with distributed tracing (OpenTelemetry)
  6. Identify bottleneck, formulate hypothesis, implement fix
  7. Re-profile to verify improvement, repeat

Security Considerations

Threat Modeling (STRIDE)

  • Spoofing: Identity validation, authentication
  • Tampering: Integrity checks, digital signatures
  • Repudiation: Audit logs, non-repudiation
  • Information disclosure: Encryption, access control
  • Denial of service: Rate limiting, resource quotas
  • Elevation of privilege: Principle of least privilege

Supply Chain Security

  • Dependency scanning: Snyk, Dependabot, Trivy
  • SBOM generation: CycloneDX or SPDX format
  • Signed commits: GPG or SSH commit signing
  • Artifact verification: Checksum validation, signature verification

Secrets Management

  • Secrets never in code — always in secrets manager (Vault, AWS Secrets Manager)
  • Rotation policy: Rotate database credentials every 90 days
  • Access audit: Log every secrets access, alert on anomalies
  • Encryption at rest and in transit for all secrets
  • Principle of least privilege: each service gets only its own secrets

Rules

  • Default-deny security posture — allow only explicitly required access.
  • All inputs validated, all outputs encoded, all errors handled.
  • Defend in depth — multiple layers of security controls.
  • Fail securely — errors default to safe behavior.
  • Log security-relevant events for audit and investigation.
  • Keep dependencies updated — automate vulnerability scanning.
  • Design for observability from day one, not as an afterthought.
  • Document all architectural decisions with rationale.
  • Review code for security, performance, and correctness before merging.

Architecture Decision Trees

QWidgets vs QML (Qt Quick)

DecisionQWidgetsQML (Qt Quick)
LanguageC++QML + JavaScript + C++ backend
RenderingCPU, rasterGPU, scene graph
UI complexityWidget-basedDeclarative, animated
PerformanceLighter for controlsBetter for fluid UI
Mobile supportLimitedExcellent
Designer toolQt DesignerQt Design Studio
Best forTools, forms, dialogsModern, animated UIs

Qt Licensing: GPL vs LGPL vs Commercial

AspectGPL v2/v3LGPL v3Commercial
Static linkingMust open sourceAllowed (unmodified lib)Allowed
DistributionSource must be providedShared libraryProprietary
CostFreeFreePaid license
SupportCommunityCommunityOfficial Qt support
Best forOpen-source appsOpen-source libsProprietary software
保存したスキル