Arrow
ArrowMarch 9, 2018, 12:35 p.m.

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

Все компилируется и запускается, но при нажатии на кнопку "Расчет" приложение вылетает.
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.

Do you like it? Share on social networks!

18
Arrow
  • March 9, 2018, 12:40 p.m.

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

    Evgenii Legotckoi
    • March 11, 2018, 9:33 a.m.

    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
      • March 11, 2018, 10:27 a.m.

      Этот код 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
        • March 11, 2018, 11:26 a.m.

        Первый раз вижу, чтобы 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
          • March 11, 2018, 11:36 a.m.

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


            Evgenii Legotckoi
            • March 11, 2018, 11:50 a.m.

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


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

              Arrow
              • March 11, 2018, 12:13 p.m.

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


                Arrow
                • March 12, 2018, 2:31 p.m.

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

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

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

                QObject(0x0)

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



                  Evgenii Legotckoi
                  • March 13, 2018, 9:59 a.m.

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

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

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

                      Evgenii Legotckoi
                      • March 13, 2018, 11:25 a.m.
                      • (edited)
                      • The answer was marked as a solution.

                      Да, конечно.


                      Вот у вас зарегистрирован некий класс в 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
                        • March 13, 2018, 11:30 a.m.

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

                          Arrow
                          • March 14, 2018, 6:25 a.m.

                          Проверил в 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
                            • March 14, 2018, 9:30 a.m.
                            • (edited)

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


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

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

                                  Arrow
                                  • March 19, 2018, 3:37 a.m.

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

                                    Evgenii Legotckoi
                                    • March 19, 2018, 5:10 a.m.

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

                                      Comments

                                      Only authorized users can post comments.
                                      Please, Log in or Sign up
                                      B

                                      C++ - Test 002. Constants

                                      • Result:16points,
                                      • Rating points-10
                                      B

                                      C++ - Test 001. The first program and data types

                                      • Result:46points,
                                      • Rating points-6
                                      FL

                                      C++ - Test 006. Enumerations

                                      • Result:80points,
                                      • Rating points4
                                      Last comments
                                      k
                                      kmssrFeb. 9, 2024, 5:43 a.m.
                                      Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                      Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                      EVA
                                      EVADec. 25, 2023, 9:30 p.m.
                                      Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                      J
                                      JonnyJoDec. 25, 2023, 7:38 p.m.
                                      Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                      G
                                      GvozdikDec. 19, 2023, 8:01 a.m.
                                      Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                      Now discuss on the forum
                                      AC
                                      Alexandru CodreanuJan. 19, 2024, 10:57 p.m.
                                      QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
                                      BlinCT
                                      BlinCTDec. 27, 2023, 7:57 p.m.
                                      Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
                                      Дмитрий
                                      ДмитрийJan. 10, 2024, 3:18 p.m.
                                      Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
                                      Evgenii Legotckoi
                                      Evgenii LegotckoiDec. 12, 2023, 5:48 p.m.
                                      Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

                                      Follow us in social networks