Политика конфиденциальностиКонтактыО сайтеОтзывыGitHubDonate
© 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")
    }
}
Что я делаю не так. В примере который смотрел реализовано так.

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

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

0

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);
Нет никакого смысла лезть в мета-объектную систему там, где это не нужно.
0

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

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

Первый раз вижу, чтобы 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();
}
Что касается ошибки, то выход за пределы массива, делаете обращение за пределы массива. При этом не вижу абсолютно никаких векторов в коде.
Включайте в режиме дебага и смотрите, где вылетает. В любом случае где-то делаете обращение к объектам раньше, чем они инициализованы.
0

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


0

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


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

0

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


0

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

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

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

QObject(0x0)

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



0

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

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

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

0

Да, конечно.


Вот у вас зарегистрирован некий класс в 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)
        }
    }
}
В результате работы этого кода, текст в текстовом поле будет заменён.
0

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

1

Проверил в 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.
0

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


Любой CMakeLists для Qt может пригодиться, по крайней мере кому-то в будущем точно.
0
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"

0

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

0

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

0

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

0

Ответы

Только авторизованные пользователи могут отвечать на форуме.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
m
19 декабря 2018 г. 10:37
maintumanov

Qt - Тест 001. Сигналы и слоты

  • Результат:68баллов,
  • Очки рейтинга-1
ИН
18 декабря 2018 г. 17:37
Игорь Носач

C++ - Тест 003. Условия и циклы

  • Результат:64баллов,
  • Очки рейтинга-1
ИН
18 декабря 2018 г. 17:22
Игорь Носач

C++ - Тест 003. Условия и циклы

  • Результат:35баллов,
  • Очки рейтинга-10
Последние комментарии
V
15 декабря 2018 г. 2:06
Vlad15007

Спасибо большое!Очень помогли!
11 декабря 2018 г. 21:01
Евгений Легоцкой

Не знаю, какой-там конкретно эффект и если честно не хочется fl studio ради того, чтобы посмотреть устанавливать, но из того, что увидел в интернете. Предполагаю, что то, что вы хотите с...
V
11 декабря 2018 г. 19:25
Vlad15007

Подскажите пожалуйста ( я новичок совсем)Можно ли организовать спрайт без этого окошка (как в fl studio fruity dance)?
11 декабря 2018 г. 15:06
Евгений Легоцкой

Что интересно, если написать так from <application_name>.<module_name> import <filename> ,то PyCharm сносит крышу, если разрабатываешь в рамках проекта приложение, ко...
11 декабря 2018 г. 14:52
Илья Чичак

Тут мне тоже есть что сказать=) Сами разрабы советуют импортировать следующим образом: from <application_name> import <module_name> Стоит избегать from . import &l...;
Сейчас обсуждают на форуме
М
19 декабря 2018 г. 8:43
Михаиллл

Здравствуйте.Говорят, если подключить ICU, то в SQLite появится регистронезависемый поиск.Я нашел скомпилированный ICU по этой ссылке https://www.npcglib.org/~stathis/blog/precompiled-...
18 декабря 2018 г. 19:58
Евгений Легоцкой

ну если у вас также будет внешний ключ на Serial, то получается следующая ситуация, Movie добавлен в Serial, а Serial имеет список Movie. То есть вам playlist как таковой вовсе не нужен....
R
18 декабря 2018 г. 12:25
RED_Spider

именно так, проблема в кодировке, а именно в отсутствии шрифтов на сервере, для меня вопрос решился в CentOS 7yum install curl cabextract xorg-x11-font-utils fontconfig всем спасибо за ...
U
18 декабря 2018 г. 10:39
Unreal_man

А вот этот коннект здесь и вовсе не нужен connect(ui->ok3, &QPushButton::clicked, this, &Widget::addToText); А как же без него? ============================== ...
m
17 декабря 2018 г. 19:03
melnik10

Спасибо, попробую!
Присоединяйтесь к нам в социальных сетях

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы