Skip to content

Commit e8e74dd

Browse files
committed
added qt example
1 parent cfbcdc1 commit e8e74dd

5 files changed

Lines changed: 176 additions & 5 deletions

File tree

conanfile.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class CppExampleProjectConan(ConanFile):
4646
"fmt/*:header_only": True,
4747
"spdlog/*:header_only": True,
4848
"qt/*:with_fontconfig": False,
49+
"qt/*:qtdeclarative": True, # QML + Quick
50+
"qt/*:qtshadertools": True, # required by QtQuick
51+
"qt/*:qtquickcontrols2": True, # ApplicationWindow, Button, etc.
4952
"open62541/*:cpp_compatible": True,
5053
}
5154

src/qt/Backend.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#pragma once
2+
3+
#include <QObject>
4+
#include <QTimer>
5+
#include <QtQml/qqmlregistration.h>
6+
7+
class Backend : public QObject
8+
{
9+
Q_OBJECT
10+
QML_ELEMENT
11+
12+
Q_PROPERTY(int elapsedSeconds READ elapsedSeconds NOTIFY elapsedSecondsChanged)
13+
Q_PROPERTY(bool running READ running NOTIFY runningChanged)
14+
15+
public:
16+
explicit Backend(QObject *parent = nullptr) : QObject(parent)
17+
{
18+
connect(&m_timer, &QTimer::timeout, this, &Backend::onTick);
19+
m_timer.setInterval(1000);
20+
}
21+
22+
[[nodiscard]] int elapsedSeconds() const { return m_elapsedSeconds; }
23+
[[nodiscard]] bool running() const { return m_timer.isActive(); }
24+
25+
public slots:
26+
void start()
27+
{
28+
m_elapsedSeconds = 0;
29+
emit elapsedSecondsChanged();
30+
m_timer.start();
31+
emit runningChanged();
32+
}
33+
34+
void stop()
35+
{
36+
m_timer.stop();
37+
emit runningChanged();
38+
}
39+
40+
void reset()
41+
{
42+
m_timer.stop();
43+
m_elapsedSeconds = 0;
44+
emit elapsedSecondsChanged();
45+
emit runningChanged();
46+
}
47+
48+
signals:
49+
void elapsedSecondsChanged();
50+
void runningChanged();
51+
52+
private slots:
53+
void onTick()
54+
{
55+
++m_elapsedSeconds;
56+
emit elapsedSecondsChanged();
57+
}
58+
59+
private:
60+
QTimer m_timer;
61+
int m_elapsedSeconds{0};
62+
};

src/qt/CMakeLists.txt

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,34 @@
1-
FIND_PACKAGE(Qt6 REQUIRED)
1+
FIND_PACKAGE(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick QuickControls2)
22

3-
ADD_EXECUTABLE(test_qt main.cpp)
4-
TARGET_LINK_LIBRARIES(test_qt PRIVATE ${CMAKE_THREAD_LIBS_INIT} qt::qt)
3+
# Enable Qt's automatic tools for this directory
4+
SET(CMAKE_AUTOMOC ON)
5+
SET(CMAKE_AUTORCC ON)
6+
7+
QT_ADD_EXECUTABLE(test_qt main.cpp)
8+
9+
# QML module: registers Backend (QML_ELEMENT) and bundles the .qml file
10+
QT_ADD_QML_MODULE(test_qt
11+
URI qt_example
12+
VERSION 1.0
13+
QML_FILES ui/main.qml
14+
SOURCES Backend.h
15+
)
16+
17+
TARGET_LINK_LIBRARIES(test_qt PRIVATE
18+
Qt6::Core
19+
Qt6::Gui
20+
Qt6::Qml
21+
Qt6::Quick
22+
Qt6::QuickControls2
23+
)
24+
25+
# Deploy Qt runtime next to the binary on Windows (requires windeployqt)
26+
IF(WIN32)
27+
ADD_CUSTOM_COMMAND(TARGET test_qt POST_BUILD
28+
COMMAND "${Qt6_DIR}/../../../bin/windeployqt.exe"
29+
--no-translations
30+
--qmldir "${CMAKE_CURRENT_SOURCE_DIR}/ui"
31+
"$<TARGET_FILE:test_qt>"
32+
COMMENT "Running windeployqt…"
33+
)
34+
ENDIF()

src/qt/main.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11

2+
#include <QGuiApplication>
3+
#include <QQmlApplicationEngine>
24

3-
int main()
5+
int main(int argc, char *argv[])
46
{
5-
return 0;
7+
QGuiApplication app(argc, argv);
8+
9+
QQmlApplicationEngine engine;
10+
11+
const QUrl url(u"qrc:/qt_example/ui/main.qml"_qs);
12+
QObject::connect(
13+
&engine,
14+
&QQmlApplicationEngine::objectCreationFailed,
15+
&app,
16+
[]() { QCoreApplication::exit(-1); },
17+
Qt::QueuedConnection);
18+
19+
engine.load(url);
20+
21+
return app.exec();
622
}

src/qt/ui/main.qml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import QtQuick
2+
import QtQuick.Controls
3+
import QtQuick.Layouts
4+
import qt_example
5+
6+
ApplicationWindow {
7+
id: root
8+
visible: true
9+
width: 480
10+
height: 320
11+
title: qsTr("Qt QML Timer Example")
12+
13+
Backend {
14+
id: backend
15+
}
16+
17+
ColumnLayout {
18+
anchors.centerIn: parent
19+
spacing: 24
20+
21+
// ---------- Timer display ----------
22+
Label {
23+
Layout.alignment: Qt.AlignHCenter
24+
text: qsTr("Elapsed: %1 s").arg(backend.elapsedSeconds)
25+
font.pixelSize: 36
26+
font.bold: true
27+
}
28+
29+
// ---------- Status text ----------
30+
Label {
31+
Layout.alignment: Qt.AlignHCenter
32+
text: backend.running ? qsTr("Timer running…") : qsTr("Timer stopped")
33+
color: backend.running ? "#2ecc71" : "#e74c3c"
34+
font.pixelSize: 16
35+
}
36+
37+
// ---------- Buttons ----------
38+
RowLayout {
39+
Layout.alignment: Qt.AlignHCenter
40+
spacing: 12
41+
42+
Button {
43+
text: qsTr("Start")
44+
enabled: !backend.running
45+
onClicked: backend.start()
46+
}
47+
48+
Button {
49+
text: qsTr("Stop")
50+
enabled: backend.running
51+
onClicked: backend.stop()
52+
}
53+
54+
Button {
55+
text: qsTr("Reset")
56+
onClicked: backend.reset()
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)