Отправка сигнала элементу QML из C++ (Qt5)

у меня есть файл QML, содержащий это:

Text {
    id: testData
    onTaskClicked:{
        testData.text = task.name
    }
}

уловка - это сигнал taskClicked. Он испускается другим виджетом (C++) и должен быть передан в QML.

это похоже на это так вопрос, за исключением того, что решение опубликовано здесь не работает (почему-написано ниже).

код C++:

ctxt->setContextProperty(QLatin1Literal("holiday"), m_model);
ctxt->setContextProperty(QLatin1Literal("bgcolor"), color);

view->setResizeMode(QQuickView::SizeRootObjectToView);

auto mainPath = QStandardPaths::locate(QStandardPaths::DataLocation,
                                           QLatin1Literal("taskview.qml"));

view->setSource(QUrl::fromLocalFile(mainPath));

ctxt->setContextProperty(QLatin1Literal("viewer"), m_view);

m_view это QListView подкласс, который выдает taskClicked(HolidayTask* task) сигнала (от .ч файл):

Q_SIGNALS:
    void taskClicked(HolidayTask* task);

color и m_model зарегистрированы в QML и используются в других местах. Объект из сигнала уже зарегистрирован в QML. view мой QQuickView.

сначала я попробовал решение, представленное в вопросе выше:

auto root = view->rootObject();
auto myElement = root->findChild<QObject*>(QLatin1Literal("testData");

connect(m_view, SIGNAL(taskClicked(HolidayTask* task), myElement,
        SLOT(taskClicked(HolidayTask* task);
, myElement всегда равно null (и я получаю предупреждение во время выполнения о несуществующем слоте).

если я попытаюсь установить указатель view (QListView) в качестве свойства контекста представления QML, он все еще не работает.

во всех случаях я получаю также:

QML Connections: Cannot assign to non-existent property "onTaskClicked"

что я могу здесь делать не так?

изменить, чтобы уточнить некоторые детали: HolidayTask является пользовательским подклассом QObject и сигналом taskClicked определяется в C++ (в A QListView подкласс)

EDIT2: мы приближаемся, но нет сигары:

auto root = quickView->rootObject();
auto myElement = root->findChild<QObject*>(QLatin1Literal("testData"));

connect(m_view, SIGNAL(taskClicked(HolidayTask*)),
        myElement, SIGNAL(taskClicked(HolidayTask* task)));

и

Text {
    id: testData
    objectName: "testData"
    signal taskClicked(HolidayTask task)
    onTaskClicked: {
        testData.text = task.name
        console.log("CLICk!")
    }
}

доходность

QObject::connect: No such signal QQuickText_QML_0::taskClicked(HolidayTask* task) in /home/lb/Coding/cpp/holiday-planner/src/mainwindow.cpp:178
QObject::connect:  (receiver name: 'testData')

больше деталей: HolidayTask, моя таможня Подкласс QObject, зарегистрирован в коде как

qmlRegisterType<HolidayTask>("HolidayPlanner", 1, 0, "HolidayTask");

минимальный QML с данными:

 import QtQuick 2.0
 import QtQml 2.2

import HolidayPlanner 1.0

Rectangle {
    id: container
    objectName: "container"
    color: bgcolor


   Text {
        id: testData
        objectName: "testData"
        signal taskClicked(HolidayTask task)
        onTaskClicked: {
            testData.text = task.name
            console.log("CLICK")
        }
   }

}

EDIT3: окончательный, рабочий код (см. ответы на почему)

 connect(m_view, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)),
        myElement, SIGNAL(taskClicked(HolidayPlanner::HolidayTask*)));

он работал только через использование объектов с полными пространствами имен. В противном случае подпись не будет совпадать в QML.

3 ответов


однако, myElement всегда null (и я получаю предупреждение о времени выполнения несуществующий слот).

вы пытаетесь найти ребенка на основе id, тогда как он основан на свойстве objectName. Вам нужно будет установить свойство objectName на желаемое, чтобы фактически найти его.

кроме того, вы, похоже, не объявляете сигнал в текстовом элементе QML. Я не уверен, является ли это пользовательским элементом C++ или встроенным. Вы не достаточно код к сожалению, понять это немного. В любом случае, объявите свой сигнал согласно документации.

поэтому, попробуйте этот код:

Text {
    id: testData
    objectName: "testData"
    // ^^^^^^^^^^^^^^^^^^^
    signal taskClicked (HolidayTask task)
    // ^^^^^^^^^^^^^^^^^^^
    onTaskClicked:{
        testData.text = task.name
    }
}

как только это будет сделано, вы почти готовы. Вы должны иметь свой HolidayTask зарегистрирован на QML точно,и вы также должны изменить синтаксис подключения в вашем основном.СРР следующим образом:

connect(m_view, SIGNAL(taskClicked(HolidayTask* task), myElement, SIGNAL(taskClicked(HolidayTask* task)));

короче говоря, вам нужно вызвать обработчик сигнала QML таким образом, а не через SLOT.

также, обратите внимание, что синтаксис connect нарушен, поскольку в нем отсутствуют заключительные скобки в конце. Это нужно исправить.

Я бы даже рассмотрел удаление назначения указателя и использование значения или ссылки на основе передачи для этого.


вы можете подключить сигнал с C++ на QML по:

 view->rootContext()->setContextProperty("testData",this);
 QObject::connect(this,SIGNAL(taskClicked(HolidayTask* task)),(QObject *)view->rootObject(),SLOT(onTaskClicked(HolidayTask* task)));

когда ваш сигнал называется taskClicked слот в QML должен быть onTaskClicked.

также в QML, вы должны назвать объект testData by:

objectName: "testData"

QML Connections: Cannot assign to non-existent property "onTaskClicked"

ошибка говорит вам, что ваш Text деталь не имеет сигнал taskClicked или собственность onTaskClicked! Нужно объявить слот внутри вашего текста. Для этого вы просто объявляете функцию:

Text {
   id: testData
   objectName: "testData" // as Laszlo said

   function onTaskClicked( task ) {
       testData.text = task.name;
   }
}

но это также не будет работать, потому что вы создаете SLOT( onTaskClicked(QVariant) ) вместо SLOT(taskClicked(HolidayTask*)). Для обмена данными с QML необходимо изменить сигнал на SIGNAL(taskClicked(QVariant)):

Q_SIGNALS:
    void taskClicked(QVariant task);

и испускают его с:

emit taskClicked( QVariant::fromValue( task ) );

помните, что для того, чтобы уметь использовать HolidayTask должно быть QObject, зарегистрированного с qmlRegisterType.

вы можете просто вызовите эту функцию qml.

если вы не можете использовать QVariant, вы можете объявить сигнал внутри текстового объекта:

Text {
   id: testData
   objectName: "testData" // as Laszlo said

   signal taskClicked ( HolidayTask task )

   onTaskClicked: {
       testData.text = task.name;
   }
}

а затем подключиться от сигнала C++ к сигналу qml:

auto root = view->rootObject(); 
auto myElement = root->findChild<QObject*>(QLatin1Literal("testData");
connect(m_view, SIGNAL(taskClicked(HolidayTask*), myElement,
    SIGNAL(taskClicked(HolidayTask*));