Privacy policyContactsAbout siteOpinionsGitHubDonate
© EVILEG 2015-2018
Recommend hosting
TIMEWEB

QML - Lesson 004. Signals and Slots in Qt QML

connections, example, qml, qml урок, qt, qt qml, qt урок, signal qml, slot qml, сигналы и слоты qml

And we got to transfer data between a layer of QML and C ++ layer. Frankly speaking, the principle is as simple as just using signals and slots in a single layer C ++. Especially in Qt 5.5.

An example will be shown on the basis of the code from the previous tutorial , where we have created a dialog box. But screenshots example works on Android will not be shown, but I assure you - Everything works like a Swiss watch.

Project Structure

Compared to the previous lesson, we had some changes. Namely, it adds a new class, which will be the core of the application.

  • appcore.h - application core file header;
  • appcore.cpp - application core source file.

And we continue to work and be with QQMLApplicationEngine. You will need to just take from the engine QML context and download it to a new class of object from which the signals in which data will be transmitted will be received.

appcore.h

Our class header file is as simple as a penny. In it there is a one meter (variable of type int), a slot that will increase the counter by one and run signal, which is also one in the class and which will transmit the counter value in QML-interface.

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>

class AppCore : public QObject
{
    Q_OBJECT
public:
    explicit AppCore(QObject *parent = 0);

signals:
    // Signal to transmit data to interface qml-interface
    void sendToQml(int count);

public slots:
    // The slot for the receiving of data from the QML-interface
    void receiveFromQml();

private:
    int count;  // Counter
};

#endif // APPCORE_H

appcore.cpp

#include "appcore.h"

AppCore::AppCore(QObject *parent) : QObject(parent)
{
    count = 0;
}

void AppCore::receiveFromQml()
{
    count++;
    emit sendToQml(count);
}

main.cpp

And here we have connected to our class interface written in QML.

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "appcore.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine; 

    AppCore appCore;    
    QQmlContext *context = engine.rootContext();   
    /* Load the object in context to establish a connection,
     * also define the name by which the connection will be
     * */
    context->setContextProperty("appCore", &appCore);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

main.qml

Here is part of the code, so as not to distract you from the main. Namely, a compound layer in QML Connections by means of the object as a target is set your class is indicated in the context. Treatment is carried out on the text name that is loaded into the QML engine context, together with the object itself.

To receive signals from the C ++ layer is necessary in the Connections register a function that will be called in much the same way as the target signal, but will start on a signal and then the name with a capital letter. That is, the following logic

  • signalToQml - on C++
  • onSignalToQml - on QML

But the call Slot will be somewhat different. For example, we have a class object in C ++, to which we refer by name appCore (declared aim in Connections). And then we call the slot. That is as follows: appCore.slotSomething (count).

Call slot in this code is done by pressing the OK button in the dialog, and in Cancel the call does not occur. At the same time, appCore object in C ++ code, the counter increases by one and causes the signal to put counter value in a text label applications.

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World") 
    color: "white"

    /* With Connections object
     * Set up a connection to the core application class
     * */
    Connections {
        target: appCore // Specify the target connection
        /* We declare and implement a function as an object parameter and 
         * first name similar to the name of the signal. 
         * The difference is that we add at the beginning on and 
         * then write with a capital letter
         * */
        onSendToQml: {
            labelCount.text = count // Set the counter to a text label
        }
    }

    MainForm {
        // Stretch the object of the main window over the parent element
        anchors.fill: parent

        // Create text label
        Text {
            id: labelCount
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.top: parent.top
            height: 300
            verticalAlignment: Text.AlignVCenter
            horizontalAlignment: Text.AlignHCenter
            text: "Hello, World !!!"
        }

        button1.style: ButtonStyle {
            // The code from the previous lesson
        }

        // Стилизуем вторую кнопку
        button2.style: ButtonStyle {
            // The code from the previous lesson
        }

        // Start a dialogue by pressing any of the buttons in the main window
        button1.onClicked: dialogAndroid.open();
        button2.onClicked: dialogAndroid.open();

        Dialog {
            id: dialogAndroid
            width: 600  // set the width of the dialog works on the desktop, but it does not work on Android
            height: 500 // set the height of the dialog works on the desktop, but it does not work on Android

            contentItem: Rectangle {
                width: 600          // Set the width, necessary for Android-devices
                height: 500         // Set the width, necessary for Android-devices
                color: "#f7f7f7"    // 

                // The area for the dialog box message
                Rectangle {
                    // The code from the previous lesson
                }

                Rectangle {
                    id: dividerHorizontal
                    // The code from the previous lesson
                }

                Row {
                    id: row
                    // The code from the previous lesson

                    Button {
                        id: dialogButtonCancel

                        // The code from the previous lesson
                        onClicked: dialogAndroid.close()
                    }

                    Rectangle {
                        id: dividerVertical
                        // The code from the previous lesson
                    }

                    Button {
                        id: dialogButtonOk

                        // The code from the previous lesson

                        onClicked: {
                            /* Before you close the dialog by clicking on OK,
                             * Send the data in the slot application core
                             * */
                            appCore.receiveFromQml()
                            // And then close the dialogue
                            dialogAndroid.close()
                        }
                    }
                }
            }
        }
    }
}

Result

The result is a simple interaction between the C ++ and QML based on all of the same signals and slots. But the result of the application you can see in the video tutorial.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
x

Не понял, как будет передаваться значение count в QML, если нигде он не описан через Q_PROPERTY

Так и будет передаваться. Это аргумент сигнала.

void sendToQml(int count);
Видите сигнатуру? аргумент называется count . Вот он и передаётся.
А описывать в Q_PROPERTY его не нужно. Не обязательно всё описывать через Q_PROPERTY . Зачастую достаточно объявлять метод сигналом, слотом или Q_INVOKABLE.
M

Статья интересная, как и реализация, но в упор ругается на

Qt\untitled1\main.cpp:21: ошибка: 'appCore' was not declared in this scope
appCore appCore;
^

А почему у вас название класса и имя переменной одинаковые?

appCore appCore;
В моём примере название класса с заглавной буквы AppCore
M
AppCore appCore;
QQmlContext *context = engine.rootContext();
context->setContextProperty("appCore", &appCore);
Вставил эти строки, ошибка никуда не делась, заголовочный файл подключен. Почему не видит класс?

Проект ваш смотреть нужно, что ещё не доделали, либо просто пересобрать билд для начала, возможно, что при создании файлов класса не обновилась информация для qmake. То есть как минимум перезапустить qmake требуется.

Огромное спасибо за статью.

В очередной раз уже выручают ваши подсказки. Если не знаю как реализовать - знаю у кого найти ответ.
Дизайнеры показали проект интерфейса, была попытка через StyleSheet, но возможностей там меньше, в итоге изучил новую для себя технологию, и проект представленный дизайнерами выглядит и работает именно так как они его себе вообразили. Из меня дизайнер фиговый и таких красивых интерфейсов я бы не нарисовал никогда. В итоге технология показала свою замечательность на 90% (остальное еще стоит изучить и возрадоваться).




Спасибо за отзыв!

V

Здраствуйте сново обращаюсь к вам. Ваш клас appcore.h и исходник appcore.cpp

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QtGui/QGuiApplication>
#include <QScreen>

#include "appcore.h"
#include <QQmlContext>



int main(int argc, char *argv[])
{

    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    AppCore appCore; 


    QQmlApplicationEngine engine;
    QQmlContext *context = engine.rootContext(); 
    context->setContextProperty("appCore", &appCore);


    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;



    return app.exec();
}

вот main.qml

V
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2

import QtQuick 2.0
import QtQuick.Window 2.2

Window {
    flags: Qt.ToolTip | Qt.FramelessWindowHint | Qt.WA_TintedBackground |Qt.WindowStaysOnTopHint

    color: "#00000000"




visible: true
width: 100
height: 460
x: (Screen.width - width)
y: (Screen.height - height)





Rectangle {
    anchors.fill: parent
    color: "transparent"


}
AnimatedSprite {


    Connections {
    target: appCore // Указываем целевое соединение
    /* Объявляем и реализуем функцию, как параметр
    * объекта и с имененем похожим на название сигнала
    * Разница в том, что добавляем в начале on и далее пишем
    * с заглавной буквы
    * */
    onSendToQml: {
    Count = count // Устанавливаем счётчик в текстовый лейбл
    }
    }




    id: sprite;
    width: 100;
    height: 100;
    anchors.centerIn: parent;
     source: "Donald.png"
     frameX: 0
     frameY: Number (count)




     frameRate: 18;
     frameWidth: 100
     frameHeight: 100
     frameCount: 6
     running: folse;

}




}


V

Вот этот момент

frame Y:

не получается перенести значения из С++

Добрый день

И что вы хотели сделать в этом коде?

    target: appCore
    onSendToQml: {
    Count = count // конкретно это, где Count в вашем коде
    }

и это

frameY: Number (count) // откуда взялся Number?
V

Думал что через:

frameY: Number (count)

буду контролировать чередование анимаций, картинка 600 на 600 с кадром 100. если сразу указать: frameCount: 36 то вся анимация пролистается, а мне необходимо конкретная строка анимации ( ну например пролистать 6 кадров с Y= 200, а потом с Y= 400)

пока на сайтах искал наткнулся на Namber, но не получилось.

Ну ок, такой тип в документации есть, но откуда-то это взяли?

Count = count // конкретно это, где Count в вашем коде

я и намёка не вижу на сам вот этот Count.

Впрочем, после пояснения уже немного яснее стало, думаю, что можете так попробовать сделать

Connections {
    target: appCore 
    onSendToQml: {
        sprite.frameY = count
    }
    }
V

Нет. Не читает. Попробывал сразу задать значение в appcore

#include "appcore.h"

AppCore::AppCore(QObject *parent) : QObject(parent)
{
    count = 200;
}

void AppCore::receiveFromQml()
{
    count++;
    emit sendToQml(count);
}

не работает, хотя без ошибок.

Чтобы работало, нужно сигнал высылать, то есть

emit sendToQml(count);

V

Спасибо огромное! Заработало!

Comments

Only authorized users can post comments.
Please, Log in or Sign up
ГК
March 20, 2019, 9:01 a.m.
Геннадий Костоянский

C++ - Test 002. Constants

  • Result:0points,
  • Rating points-10
ГК
March 20, 2019, 8:46 a.m.
Геннадий Костоянский

C++ - Test 002. Constants

  • Result:25points,
  • Rating points-10
Last comments
MU
March 20, 2019, 3:43 p.m.
Maciej Urmański

It's possible to simply add vote option for non logged users?
March 20, 2019, 9:45 a.m.
Евгений Легоцкой

Добрый день. Поппробуйте домен localhost, а url соответственно http://localhost Возможно, потребуется указать порт. Например, так http://localhost:8000
March 19, 2019, 12:57 p.m.
AlexanderBardin

Добрый день. А проверить работоспособность локально как-то можно не указывая реальнй сайт (еще в разработке)
March 16, 2019, 1:55 p.m.
Дмитрий

Спасибо за статью. Давно итересует следующий вопрос: с помощью переменных QMAKE_TARGET_COMPANYQMAKE_TARGET_PRODUCTQMAKE_TARGET_DESCRIPTIONможно задать свойства компилируемой программы, о...
JS
March 12, 2019, 10:19 a.m.
Jean Stefanovich

Большое спасибо за разъяснения!
Now discuss on the forum
March 20, 2019, 12:26 p.m.
Евгений Легоцкой

Лучше стараться избегать этого. Нормального механизма нет. Я просто выдёргиваю из бэкенда перевёденные куски шаблона, если нужно что-то задействовать в JS.
March 17, 2019, 10:47 p.m.
Евгений Легоцкой

Добрый день. Вот, нашлось у меня немного времени. Делается это через шаблон проектирования наблюдатель. GraphKS_mfvSlup.zip
ЧГ
March 15, 2019, 9:52 p.m.
Чарльз Грин

спасибо, попробую, отпишусь
m
March 15, 2019, 7:41 p.m.
mihamuz

Сори догадался)
n
March 12, 2019, 4:57 p.m.
newbie.works.with.QT

Большооооое спасибо!!!!!Не передать как я вам благодарен, спасибо что всегда отзываетесь.Теперь я смогу продолжить работу в QT!!! (пробую писать бота (Я как вы могли догадаться немного не пр...
Join us in social networks

For registered users on the site there is a minimum amount of advertising