Miloš Kozák
Miloš Kozák

Reputation: 3

C++ signals and accessing QtQuick items

I am trying to write an QtQuick program which works as an intelligent interface between user and a few CLI applications. I have implemented QtQuick + JavaScript application.

A QtQuick butten emits signal that is listened by C++ layer. So far everything works well.

However, in my C++ slot function I need to write to a certain Item in QtQuick application. This Item is an TextArea which serves as Log output of CLI applications. These CLI applications are run from the slot function in C++. I store their output into a variable, and I want to show output of this variable in this Log output TextArea.

I tried a lot of things, but I didn't find the right way to do that

Upvotes: 0

Views: 160

Answers (2)

Miloš Kozák
Miloš Kozák

Reputation: 3

My final solution of main function looks like this:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;

    AnalyzeSignal analyzeSignal;
    QQmlContext *context = engine.rootContext();
    context->setContextProperty("analyzeSignal", &analyzeSignal);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    // Registering slot onto a signal
    QObject *win = engine.rootObjects()[0];
    QObject *item = win->findChild<QObject*>("myButton");
    QObject::connect(item, SIGNAL(doAnalyzeSignal(QString,QString,QString,QString)), &analyzeSignal, SLOT(cppSlot(QString,QString,QString,QString)));

    return app.exec();
}

And this works!

Upvotes: 0

dfranca
dfranca

Reputation: 5322

I'd a similar problem. This is how I solved it.

In C++ I created a class that handles the command with a QProcess (and I expose the class to QML), which attach the readyToRead signal to a C++ function in my exposed class, this function emits another signal showOutput with the output text.

With this information I just connect my new signal to a javascript function in qml:

cppExposed.showOutput.connect(jsFunction);

And in the javascript function I just append the text

function jsFunction(output) {
    OutputTextArea.text += output;
}

To expose C++ properties to QML you can have a look at the documentation here: http://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html

I think the easiest way for you is to create an object of your cpp class, and set as a context property in your main.cpp before load your main.qml: Something like this:

QQmlApplicationEngine engine;
ProcessHandler procHandler;
engine.rootContext()->setContextProperty("procHandler", &procHandler);

Now you can access your object direct from QML, and you can connect signals

procHandler.showOutput.connect(jsFunction)

And in your C++ class don't forget to connect with the process ReadyToReady signal and emit your own signal with the data:

void readyToRead() {
    emit showOutput(m_proc.readAllStandardOutput());
}

UPDATE: Your property should be set before load the QML file by the engine:

AnalyzeSignal analyzeSignal;
engine.rootContext()->setContextProperty("analyzeSignal", &analyzeSignal);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

And I don't think you need that writeToLogOutput to be a property (and it has some syntax error btw), it's a signal method, right? So it's automatically available to QML as a signal, not a property.

DON'T create a new QQMLContext. In this line what you are doing is creating a new QQMLContext

QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextProperty("analyzeSignal", &analyzeSignal);

This won't work, as you are setting the property to the newly created context, not to the original root context.

Upvotes: 2

Related Questions