Skip to main content
Preskoči na vsebino

Povežite logiko s svojim uporabniškim vmesnikom QML

Povežite zaledje za opravljanje izračunov in oskrbovanje uporabniškega vmesnika s podatki za prikaz

Za integracijo logike v aplikacijo potrebujemo razrede zalednega sistema C++, ki lahko izvajajo pomembne izračune. Pisanje logike v datoteke QML ni priporočljivo, zato poskusite čim več logike premakniti v zaledni sistem, tako da se QML uporablja samo za prikaz uporabniškega vmesnika.

Uporabili bomo kodo vadnice Uporaba ločenih datotek v projektu C++ kot osnovo.

Struktura projekta

kirigami-tutorial/
├── CMakeLists.txt
├── org.kde.tutorial.desktop
└── src/
    ├── CMakeLists.txt
    ├── main.cpp
    ├── Main.qml ----------------------- # Modified
    └── components/
        ├── CMakeLists.txt ------------- # Modified
        ├── AddDialog.qml
        ├── KountdownDelegate.qml
        ├── ExposePage.qml ------------- # New
        ├── backend.h ------------------ # New
        └── backend.cpp ---------------- # New

Spremembe obstoječe kode

src/components/backend.h

Najprej ustvarite datoteko glave, ki bo vsebovala kodo, izpostavljeno QML, in sicer zvrsti Backend:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#pragma once

#include <QObject>
#include <qqmlintegration.h>

class Backend : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON

public:
    explicit Backend(QObject *parent = nullptr);
};

Za izpostavljanje kode C++ v QML sta potrebni dve stvari, ena od njiju pa je preprosta uporaba makra QML_ELEMENT, ki je na voljo v glavi <QtQml/qqmlregistration.h>.

Zaledni del bo ustvarjen kot singleton, kar pomeni, da bo ustvarjen samo enkrat in bo obstajal celotno življenjsko dobo aplikacije. Za to uporabljamo makro QML_SINGLETON.

src/components/backend.cpp

Začetno kodo za konstruktor lahko dodamo v backend.cpp:

1
2
3
4
5
#include "backend.h"

Backend::Backend(QObject *parent)
    : QObject(parent)
{}

src/components/ExposePage.qml

Od zdaj naprej bo zaledni del (backend) v QML znan kot zvrst QML Backend. Vsebuje ga modul z imenom org.kde.tutorial.components.

To pomeni, da je z dodajanjem uvoza v datoteko QML mogoče uporabiti kodo, izpostavljeno iz C++:

import org.kde.tutorial.components

Če želite začeti iz nič z obstoječo kodo aplikacije, ustvarite novo komponento QML, ki vsebuje prazno stran:

1
2
3
4
5
6
7
import org.kde.kirigami as Kirigami
import org.kde.tutorial.components

Kirigami.Page {
    title: "Exposing to QML Tutorial"
    // ...
}

src/Main.qml

Da bi dejansko prikazali novo stran, ustvarimo možnost menija, ki novo stran potisne v aplikacijo, da bomo lahko model lažje preizkusili.

Za to lahko uporabimo novo Kirigami.Action skupaj z Qt.createComponent() za sprotno generiranje strani:

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    globalDrawer: Kirigami.GlobalDrawer {
        isMenu: true
        actions: [
            Kirigami.Action {
                text: i18n("Exposing to QML")
                icon.name: "kde"
                onTriggered: pageStack.push(Qt.createComponent("org.kde.tutorial.components", "ExposePage"))
            },
            Kirigami.Action {
                text: i18n("Quit")
                icon.name: "application-exit-symbolic"
                shortcut: StandardKey.Quit
                onTriggered: Qt.quit()
            }
        ]
    }

src/components/CMakeLists.txt

Nazadnje v CMake dodajte novo ustvarjene datoteke backend.h, backend.cpp in ExposePage.qml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
add_library(kirigami-hello-components)

ecm_add_qml_module(kirigami-hello-components
    URI "org.kde.tutorial.components"
    GENERATE_PLUGIN_SOURCE
)

ecm_target_qml_sources(kirigami-hello-components
    SOURCES
    AddDialog.qml
    KountdownDelegate.qml
    ExposePage.qml
)

target_sources(kirigami-hello-components
    PRIVATE
    backend.cpp backend.h
)

ecm_finalize_qml_module(kirigami-hello-components)

install(TARGETS kirigami-hello-components ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})

Dodajanje datotek obstoječemu modulu QML v CMake je drugi del izpostavljanja kode QML.

Upoštevajte, da bi moral biti modul QML ustvarjen z ecm_add_qml_module() ali qt_add_qml_module(), saj sta potrebna za deklarativno registracijo.

Zdaj bi morali biti sposobni prevesti in namestiti projekt z enakimi koraki kot prej.

Naredimo ga funkcionalnega

src/components/backend.h

Zdaj smo razred, ki drži bodočo logiko, povezali z aplikacijo, a še vedno ne naredi ničesar. Če želite to spremeniti, dodajmo lastnost razredu. Lastnosti so veliko več kot preprosta spremenljivka. Uporabniški vmesnik lahko obvestijo o spremembah, tako da lahko posodobijo prava področja.

Tik pod makrom QML_SINGLETON dodajte novo lastnost Q_PROPERTY.

Q_PROPERTY(QString introductionText READ introductionText WRITE setIntroductionText NOTIFY introductionTextChanged)

To se morda zdi veliko kode, samo za to da preberete in napišete nekaj kode iz zaledja. Vendar natančnejši pogled razkriva, da branje lastnosti iz uporabniškega vmesnika že lahko zažene nekaj logike - in enako, kadar je zapisujemo. V tem primeru bo samodejno obvestilo začelje in zaledje o spremembah.

Branje in pisanje temeljita na funkcijah getter in setter. Nadaljujte in dodajte nov zasebni atribut vašemu razredu, kot je ta, in dodajte funkciji getter in setter.

Dodajte nov zasebni razdelek z naslednjim:

private:
    QString m_introductionText = QStringLiteral("Hello World!");

In obstoječemu javnemu razdelku dodajte naslednje:

public:
    QString introductionText() const;
    void setIntroductionText(const QString &introductionText);
    Q_SIGNAL void introductionTextChanged();

Prva funkcija je getter, druga setter, tretja pa signal, ki se odda ob spremembi lastnosti. Ujemajo se z deli READ, WRITE in NOTIFY zgornje funkcije Q_PROPERTY.

Rezultat bi moral biti podoben naslednjemu:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#pragma once

#include <QObject>
#include <qqmlintegration.h>

class Backend : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
    Q_PROPERTY(QString introductionText READ introductionText WRITE setIntroductionText NOTIFY introductionTextChanged)
public:
    explicit Backend(QObject *parent = nullptr);
    QString introductionText() const;
    void setIntroductionText(const QString &introductionText);