Arrow
Arrow9 марта 2018 г. 12: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")
    }
}
Что я делаю не так. В примере который смотрел реализовано так.

Все компилируется и запускается, но при нажатии на кнопку "Расчет" приложение вылетает.
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

18
Arrow
  • 9 марта 2018 г. 12:40

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

    Evgenii Legotckoi
    • 11 марта 2018 г. 9:33

    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);
    Нет никакого смысла лезть в мета-объектную систему там, где это не нужно.
      Arrow
      • 11 марта 2018 г. 10:27

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

      ASSERT failure in QList<T>::operator[]: "index out of range", file /usr/include/x86_64-linux-gnu/qt5/QtCore/qlist.h, line 545
        Evgenii Legotckoi
        • 11 марта 2018 г. 11:26

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

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


            Evgenii Legotckoi
            • 11 марта 2018 г. 11:50

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


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

              Arrow
              • 11 марта 2018 г. 12:13

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


                Arrow
                • 12 марта 2018 г. 14:31

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

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

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

                QObject(0x0)

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



                  Evgenii Legotckoi
                  • 13 марта 2018 г. 9:59

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

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

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

                      Evgenii Legotckoi
                      • 13 марта 2018 г. 11:25
                      • (ред.)
                      • Ответ был помечен как решение.

                      Да, конечно.


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

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

                          Arrow
                          • 14 марта 2018 г. 6:25

                          Проверил в 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.
                            Evgenii Legotckoi
                            • 14 марта 2018 г. 9:30
                            • (ред.)

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


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

                                Arrow
                                • 14 марта 2018 г. 10:25

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

                                  Arrow
                                  • 19 марта 2018 г. 3:37

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

                                    Evgenii Legotckoi
                                    • 19 марта 2018 г. 5:10

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

                                      Комментарии

                                      Только авторизованные пользователи могут публиковать комментарии.
                                      Пожалуйста, авторизуйтесь или зарегистрируйтесь
                                      B

                                      C++ - Тест 002. Константы

                                      • Результат:16баллов,
                                      • Очки рейтинга-10
                                      B

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

                                      • Результат:46баллов,
                                      • Очки рейтинга-6
                                      FL

                                      C++ - Тест 006. Перечисления

                                      • Результат:80баллов,
                                      • Очки рейтинга4
                                      Последние комментарии
                                      k
                                      kmssr9 февраля 2024 г. 5:43
                                      Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                      АК
                                      Анатолий Кононенко5 февраля 2024 г. 12:50
                                      Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                      EVA
                                      EVA25 декабря 2023 г. 21:30
                                      Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                      J
                                      JonnyJo25 декабря 2023 г. 19:38
                                      Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                      G
                                      Gvozdik19 декабря 2023 г. 8:01
                                      Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                      Сейчас обсуждают на форуме
                                      P
                                      Pisych27 февраля 2023 г. 15:04
                                      Как получить в массив значения из связанной модели? Спасибо, разобрался:))
                                      AC
                                      Alexandru Codreanu19 января 2024 г. 22:57
                                      QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
                                      BlinCT
                                      BlinCT27 декабря 2023 г. 19:57
                                      Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
                                      Дмитрий
                                      Дмитрий10 января 2024 г. 15:18
                                      Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
                                      Evgenii Legotckoi
                                      Evgenii Legotckoi12 декабря 2023 г. 17:48
                                      Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

                                      Следите за нами в социальных сетях