© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB
9 марта 2018 г. 17:35

Связь интерфейса QML с C++

QML C++, интерфейс

Первый раз пытаюсь работать с QML.

Пытаюсь написать самое простое, что только есть - сложение двух чисел.

Не выходит ничего. Делаю так.

Код:

Файл main.cpp:

 
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "myclass.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    qputenv("QT_LABS_CONTROLS_STYLE", QVariant("Material").toByteArray());

    const QUrl mainQml(QStringLiteral("qrc:/main.qml"));

    const QMetaObject::Connection connection = QObject::connect(
                &engine, &QQmlApplicationEngine::objectCreated,
                &app, [&](QObject *object, const QUrl &url) {
            if (url != mainQml)
            return;

            if (!object)
            app.exit(-1);
            else
            QObject::disconnect(connection);
}, Qt::QueuedConnection);

    engine.load(mainQml);

    QObject* root = engine.rootObjects()[0];
    MyClass(root);
    engine.rootContext()->setContextProperty("myClass", &myClass);

    return app.exec();
}

В файле myclass.h:
 
public:
    Q_INVOKABLE void func();
В файле myclass.cpp:
 
void MyClass::func()
{
    QObject* numberX = viewer->findChild<QObject*>("numberX");
    QObject* numberY = viewer->findChild<QObject*>("numberY");

    QObject* resultLabel = viewer->findChild<QObject*>("resultLabel");

    QString str1 = (numberX->property("text")).toString();
    QString str2 = (numberY->property("text")).toString();

    int c = str1.toInt() + str2.toInt();

    resultLabel->setProperty("text", str1 + " + " + str2 + " = " + QString::number(c));
}
Файл main.qml:
 
import QtQuick 2.7
import QtQuick.Controls 1.5

ApplicationWindow {
    visible: true
    width: 250
    height: 230
    title: qsTr("QmlTest")

    Label {
        id: label
        x: 23
        y: 9
        text: qsTr("Сумма двух чисел")
    }

    Label {
        id: label1
        x: 23
        y: 48
        text: qsTr("Число 1:")
    }

    Label {
        id: label2
        x: 23
        y: 97
        text: qsTr("Число 2:")
    }

    Label {
        id: resultLabel
        objectName: resultLabel
        x: 23
        y: 140
        width: 70
        height: 20
        text: qsTr("Результат:")
    }

    TextField {
        id: numberY
        objectName: numberY
        x: 99
        y: 92
        width: 130
        height: 30
    }

    TextField {
        id: numberX
        objectName: numberY
        x: 99
        y: 40
        width: 130
        height: 30
    }

    Button {
        id: calckBtn
        x: 23
        y: 183
        width: 80
        text: qsTr("Расчет")
    }

    Connections {
        target: calckBtn
        onClicked: myClass.func()
    }

    Connections {
        target: exitBtn
        onClicked: Qt.quit()
    }

    Button {
        id: exitBtn
        x: 149
        y: 183
        width: 80
        text: qsTr("Exit")
    }
}
Что я делаю не так. В примере который смотрел реализовано так.

Все компилируется и запускается, но при нажатии на кнопку "Расчет" приложение вылетает.
  • #
  • 9 марта 2018 г. 17:40

В файле myclass.h: QObject *viewer;

setContextProperty нужно использовать до загрузки qml файла в движок.

Посмотрите пример в этой статье

Зачем вот всё это? В каком примере Вы всё это увидели?
const QMetaObject::Connection connection = QObject::connect(
                &engine, &QQmlApplicationEngine::objectCreated,
                &app, [&](QObject *object, const QUrl &url) {
            if (url != mainQml)
            return;

            if (!object)
            app.exit(-1);
            else
            QObject::disconnect(connection);
}, Qt::QueuedConnection);
Нет никакого смысла лезть в мета-объектную систему там, где это не нужно.

Для Django рекомендую VDS-хостинг TIMEWEB

Этот код QtCreator сам сгенерировал.
Сделал как в примере, приложение вообще не запускается, пишет:

ASSERT failure in QList<T>::operator[]: "index out of range", file /usr/include/x86_64-linux-gnu/qt5/QtCore/qlist.h, line 545

Первый раз вижу, чтобы QtCreator генерировал код с MetaObject::Connection. Какой именно проект запускали?

Специально создал пустой проект с QML и вижу, что там ничего подобного не создаётся.
#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

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

    return app.exec();
}
Что касается ошибки, то выход за пределы массива, делаете обращение за пределы массива. При этом не вижу абсолютно никаких векторов в коде.
Включайте в режиме дебага и смотрите, где вылетает. В любом случае где-то делаете обращение к объектам раньше, чем они инициализованы.

Для Django рекомендую VDS-хостинг TIMEWEB

Проект на QtQuick (не пустой) креатор последний


Ок, скачал бету, проверил. Действительно, есть подключение мета-объектной системы. У меня вопрос: Зачем Вы используете Бету креатора?
Впрочем, ваше право - сидеть на нестабильном софте.


Касательно выхода за пределы массива, рекомендация остаётся той же самой, пройдитесь через дебагер. В представленном коде не вижу ничего такого, что могло бы быть ошибочно, кроме того, что я сказал по поводу установки контекста до загрузки qml файла в движок. Сначала установить контекст, потом грузить файл qml в движок.

Для Django рекомендую VDS-хостинг TIMEWEB

Я в нем только проект генерировал. Сам я сижу на CLion.


Такая конструкция не работает:

QObject* numberX = this->findChild<QObject*>("numberX");

Получается такой результат:

QObject(0x0)

Есть ли возможность заменить эту конструкцию, я пока не смог найти ответа.



Здесь Вы выбрали неправильного парента, в котором пытаетесь найти потомков, полагаю, что те объекты из QML слоя. Можете найти потомков через root объекты в QQmlAplicationEngine, метода rootObjects.

либо создавайте Q_INVOKABLE методы через которые сможете передать указатель на объект из QML в C++. Когда создаёте Q_INVOKABLE метод с указателем на QObject , то в этот метод в QML слое можно передавать id объекта в QML .

Для Django рекомендую VDS-хостинг TIMEWEB

А если не сложно, можно пример передачи id объекта QML. Именно как это написать в main.qml.

Да, конечно.


Вот у вас зарегистрирован некий класс в C++ в качестве контекста в QML и он имеет метод, который принимает указатель на QObject класс в качестве аргумента.

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>

class AppCore : public QObject
{
    Q_OBJECT
    using BaseClass = QObject;
public:
    explicit AppCore(QObject *parent = nullptr);
    // Метод, который принимает некоторый указатель на QObject
    Q_INVOKABLE void receiveFromQml(QObject* someObject);

signals:

public slots:
};

#endif // APPCORE_H
Реализация класса
#include "AppCore.h"

#include <QDebug>

AppCore::AppCore(QObject *parent) :
    BaseClass(parent)
{

}

void AppCore::receiveFromQml(QObject *someObject)
{
    someObject->setProperty("text", "Hello world");
}
Как он зарегистрирован в QML
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "AppCore.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

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

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

    return app.exec();
}
И далее, как это работает в QML
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Text {
        id: text
        text: qsTr("Empty Text")
        anchors.centerIn: parent
    }

    Button {
        text: qsTr("Press Me")
        anchors.top: text.bottom
        anchors.topMargin: 20
        anchors.horizontalCenter: parent.horizontalCenter

        onClicked: {
            // Просто передаём id текстового поля. В данном случае будет передан указатель на QObject
            appCore.receiveFromQml(text)
        }
    }
}
В результате работы этого кода, текст в текстовом поле будет заменён.

Для Django рекомендую VDS-хостинг TIMEWEB

Огромное спасибо!!!

Проверил в Linux Debian 9 64bit (Qt 5.10), компилятор Clang - все работает.

В Windows 7 64 bit (Qt5.10), компилятор Clang - Запускается, но при появлении окна вылетает: Process finished with exit code -1073741819 (0xC0000005).

PS. Если интересно могу выложить почти "универсальный" CMakeLists для работы с Qt.

Могу предположить только то, что там может быть баг, как вариант под Windows стоит попробовать собрать с помощью MSVC.


Любой CMakeLists для Qt может пригодиться, по крайней мере кому-то в будущем точно.

Для Django рекомендую VDS-хостинг TIMEWEB

CMakeLists.txt:


cmake_minimum_required(VERSION 3.1)

# Имя проекта ProjName
project(ProjName LANGUAGES CXX)

# Искать подключаемые файлы в директории сборки
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

# C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Компилятор Clang для C
SET (CMAKE_C_COMPILER             clang)
# Флаги
SET (CMAKE_C_FLAGS                "-Wall -std=c99")
SET (CMAKE_C_FLAGS_DEBUG          "-g")
SET (CMAKE_C_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
SET (CMAKE_C_FLAGS_RELEASE        "-O3 -DNDEBUG")
SET (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")

# Компилятор Clang для C++
SET (CMAKE_CXX_COMPILER clang++)
# Флаги
set(CMAKE_CXX_FLAGS                "-Wall -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG          "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL     "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE        "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")

# Авто поиск *.cpp, *.h, *.ui, *.qrc в директории проекта (без поддиректорий)
FILE(GLOB SOURCE_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
FILE(GLOB HEADER_FILES ${PROJECT_SOURCE_DIR}/*.h)
FILE(GLOB UI_SRC_FILES ${PROJECT_SOURCE_DIR}/*.ui)
FILE(GLOB UI_QRCS ${PROJECT_SOURCE_DIR}/*.qrc)

# Иконка приложения для Windows
FILE(GLOB ICON_RCS ${PROJECT_SOURCE_DIR}/*.rc)

# Модули Qt (Widgets, QtGui, QtCore, QtPrintSupport)
find_package(Qt5 COMPONENTS Widgets PrintSupport REQUIRED)

# Ресурсы *.qrc
qt5_add_resources(UI_RESOURCES_RCC ${UI_QRCS})

# Папка для релиз версии исп. файла
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    if(WIN32)
        set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Winows)
    elseif(UNIX)
        set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Linux)
    endif()
endif()

# Исп. файл
if(WIN32)
    add_executable(${PROJECT_NAME} WIN32 ${SOURCE_FILES} ${HEADER_FILES}
        ${UI_SRC_FILES} ${UI_RESOURCES_RCC} ${ICON_RCS})

    # Qt модули
    target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::PrintSupport)    
else()
    add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES}
        ${UI_SRC_FILES} ${UI_RESOURCES_RCC})

    target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::PrintSupport)
endif()
Файл для иконки приложения logo.rc:

IDI_ICON1 ICON DISCARDABLE "ProjICO.ico"

Как внести информацию о компании версии программы и т.д. не нашел, если кто знает как пишите :)

Проблема с запуском наблюдается только при компиляции на Windows 64 bit версии программы, 32 bit работает без проблем.

Тогда на MSVC собирайте, а не на Clang. С MSVC я проблем не наблюдал, может, конечно, что-то всплыть и там, но ... другого варианта всё равно на данный момент нет.

Для Django рекомендую VDS-хостинг TIMEWEB

Ответы

Только авторизованные пользователи могут отвечать на форуме.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
24 сентября 2018 г. 17:42
edorofeeva

C++ - Тест 001. Первая программа и типы данных

  • Результат 100баллов,
  • Очки рейтинга10
24 сентября 2018 г. 17:37
edorofeeva

C++ - Тест 001. Первая программа и типы данных

  • Результат 66баллов,
  • Очки рейтинга-1
23 сентября 2018 г. 14:38
No Names

C++ - Тест 001. Первая программа и типы данных

  • Результат 60баллов,
  • Очки рейтинга-1
Последние комментарии
24 сентября 2018 г. 15:09
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

А вот здесь у меня есть пример использования supervisor. https://evileg.com/ru/post/3/ Вся статья вам там не интересна, интересен только шаг с настройкой supervisor. Он получается ...
24 сентября 2018 г. 15:00
avovana

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Не могли бы дать ссылку на пример? Какое-то рабочее использование. Т.е. у меня есть Qt Gui App, которое я бы хотел запускать при старте системы и в случае, если оно грохнется. Если о чем Вы го...
24 сентября 2018 г. 14:55
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Если честно, то я не уверен, что это вообще можно реализовать через *.desktop файл. Я сделал предположение на основе того, что вы сказали про *.desktop и рестарт. Все варианты, котор...
24 сентября 2018 г. 14:47
avovana

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Просто сейчас правлю сам файл example.desktop. Пытаюсь понять какую пару key=value мне нужно дописать.
24 сентября 2018 г. 14:42
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

Ну я имел ввиду, что дописать в коде вот сюда то, о чём вы говорили про рестарт QString autorunContent("[Desktop Entry]\n" "Type=Application\n" ...
Сейчас обсуждают на форуме
24 сентября 2018 г. 16:47
Евгений_Канусовский@1981

Чтение файлов в python

Добрый вечер Евгений и форумчане! Столкнулся с проблемой чтения файлов в python: файлы с обычным текстом в формате las и txt читаются, например: ~Version information VERS.          ...
24 сентября 2018 г. 13:29
Евгений Легоцкой

Трансляция видео с помощью VLC по RTP

Добрый день! Я не сталкивался, но предположу, что нужно настроить Input Codec в VLC. В настройках есть секция Input Codec, возможно, что там установлено низкое разрешение. ...
21 сентября 2018 г. 8:25
Евгений Легоцкой

Прокси-модель, содержащая на 1 столбец больше, чем модель-источник.

Попробуйте ещё PySide 2 - это официально поддерживаемый пакет привязок Python к Qt, возможно, что там не будет таких проблем.
20 сентября 2018 г. 20:06
Евгений Легоцкой

Qt Installer Framework

Добрый день. Зачем собирать Qt Installer Framework-то из исходников? Я ещё понимаю Qt собирают из исходников статически (хотя тоже считаю по большей части бесполезной тратой времени),...
Присоединяйтесь к нам в социальных сетях