Exchange data from C++ to QML - c++

And sorry about the vague title, i don't know how to express it better, so pardon me.
I got a class to store data, inherit from QObject, and a loginSignal
class UserData : public QObject {
Q_OBJECT
public:
Q_INVOKABLE QString login(const QString p_user, const QString p_password, const bool p_remember);
UserData(QObject* parent = 0);
signals:
void userLogin();
};
Register class to QML
qmlRegisterType<UserData>("UserData",1,0,"UserData");
Connect to a QML Element
ApplicationWindow {
UserData {
id:userData
}
Rectangle {
Connections {
target: userData
onUserLogin : {
doSomething()
}
}
}
}
However if i call emit(userLogin()) signal inside login() function, nothing happend in QML
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine(QUrl("qrc:///mainControl.qml"));
QQmlContext* context = engine.rootContext();
UserData userData;
context->setContextProperty("userData",&userData);
userData.login(user, pass, true);
return app.exec();
}
Maybe QML Component hasn't complete finished yet?
And thank for dropping by
Edit : Look like i accident create a second instance in QML, and use it. Everything working fine now :D

Related

Routinely change QML property value from within a threaded c++ loop

I'm brand new to c++ and QML, and am struggling to call and run a threaded loop. I'd like to add an integer to a QML propery value every x milliseconds.
I'll omit my main.qml code for now, as I'm able to access the desired property; this question pertains more to c++.
void fn(QQuickItem x)
{
for (;;)
{
std::this_thread::sleep_for(std::chrono.milliseconds(100));
x->setProperty("value", x->property("value").toReal() + 10);
}
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
//QScopedPointer<TachometerDemo> Tacho(new TachometerDemo);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QQuickItem *item = engine.rootObjects().at(0)->findChild<QQuickItem*>
("circularGauge");
thread t1(fn, item);
return app.exec();
}
Any guidance on the most efficient means for achieving the above desired functionality would be appreciated. Whilst I'm currently testing on a win32 platform, a cross-platform approach is required.
Better use Qt's event loop mechanism and SIGNAL/SLOTS. And QThreads if needed. Also if you need to update value in QML in msecconds duration don't do it over setProperty, this function call takes too long. You can update your value directly in QML using JS. But if you need to update QML value from C++ you can do it this way:
test.h
#include <QObject>
#include <QTimer>
class Test : public QObject
{
Q_OBJECT
public:
Test();
Q_PROPERTY(int value READ value NOTIFY valueChanged)
int value(){return this->m_value;}
signals:
void valueChanged();
private slots:
void timeout();
private:
int m_value;
QTimer * m_timer;
};
test.cpp
#include "test.h"
Test::Test():m_value(0)
{
this->m_timer = new QTimer(this);
this->m_timer->setInterval(100);
connect(this->m_timer, &QTimer::timeout, this, &Test::timeout);
this->m_timer->start();
}
void Test::timeout()
{
this->m_value += 10;
emit valueChanged();
}
in your main.cpp
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty(QStringLiteral("Test"), new Test());
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
Somewhere in your QML:
Label
{
text: Test.value
anchors.centerIn: parent
}
This is the fastest way to update QML value from C++

QWidget Application w/QML and Registered Types

I have a QWidget application that makes use of QML. I have a class that I'm using to expose some of our organizations utility functions.
I have boiled the problem down to the following code (I'll explain my problem below the code):
First, here is the main.cpp file (I've excluded most of the includes for brevity):
#include "main.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
Here is the included main.h:
class MyUtils : public QObject
{
Q_OBJECT
public:
MyUtils(QObject* parent = nullptr)
: QObject(parent)
{
}
virtual ~MyUtils() = default;
Q_INVOKABLE QString doSomething()
{
return QString("I did something!");
}
static QObject* MyUtilsProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
qDebug() << "MyUtils Invoked!";
return new MyUtils();
}
};
class MyView : public QQuickWidget
{
Q_OBJECT
public:
MyView(QWidget* parent = nullptr)
: QQuickWidget(parent)
{
setResizeMode(QQuickWidget::SizeRootObjectToView);
setSource(QUrl("qrc:/main.qml"));
}
virtual ~MyView() = default;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
QTabWidget _tabView;
public:
MainWindow(QWidget * parent = 0)
: QMainWindow(parent)
{
qmlRegisterSingletonType<MyUtils>("MyUtilities", 1, 0, "myutils", &MyUtils::MyUtilsProvider);
setCentralWidget(&_tabView);
_tabView.addTab(new MyView(), "Tab 1");
}
};
And last, here is my QML file:
import QtQuick 2.1
import MyUtilities 1.0
Rectangle
{
Text
{
text: myutils.doSomething()
anchors.centerIn: parent
}
}
What I am trying to do is register the MyUtils class as a singleton that I can then include in my QML and use. The problem is that when I run this, I get the following message from the Application's output:
QML debugging is enabled. Only use this in a safe environment.
Qml debugging is enabled. Only use this in a safe environment!
qrc:/main.qml:8: ReferenceError: myutils is not defined
I have tried putting qmlRegisterSingletonType in main(), before the instantiation of the QApplication object (and in various other places for giggles) but so far I have not been able to get this to work.
I have noticed that if I put a breakpoint or qDebug() message in the MyUtils::MyUtilsProvider method, it never gets called. This leads me to think that maybe my MyView class is using a different QQmlEngine object than the one in which the qmlRegisterSingletonType is registering the singleton with. But if that's the case, then I don't know how to get that engine to then pass to the MyView constructor.
Can someone please tell me what I am doing wrong and how I can get this to work?
Thank you!
QML component names must begin with capital letters:
qmlRegisterSingletonType<MyUtils>("MyUtilities", 1, 0, "Myutils",
&MyUtils::MyUtilsProvider);
and thus
text: Myutils.doSomething()

Add ListView sections based on c++ QStringList model

The QStringList I'am providing to my QML ListView is displayed correctly. Now I want to reorganize the strings into sections but I'am kind of stuck on what to provide to the section.property ! Is there a minimal change I can make to my code to provide this info ?
Here is my code so far:
C++ Class:
class Foo : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList data READ getData WRITE setData NOTIFY dataChanged)
public:
QStringList getData() const {return m_data;}
void setData(const QStringList &data);
signals:
void dataChanged();
private:
QStringList m_data;
};
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Foo>("MyModule", 1, 0, "Foo");
QQuickView view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();
return app.exec();
}
main.qml
import MyModule 1.0
Foo{
id: foo
}
...
ListView {
id: myView
model: foo.data
delegate: Text {text: modelData}
section {
property: what should I write in here ?
}
}

QtQuick2 Can't connect ApplicationWindow closing signal to method (C++ novice)

I'm having trouble binding an "On Close" event for my application written in QtQuick. What I'd like to do is do the standard "confirm exit" method and maybe I'm going about this the wrong way.
As I understand it I want something like
void MainDriver::onClose(QEvent* event)
{
if(notSaved)
{
//prompt save
event->ignore();
}
else
event->accept();
}
however it seems QQuickCloseEvent isn't derived from QEvent or I'm including the wrong header (very possible) and I can't find out where it is defined so that I can connect the signals.
Is there a better way to get around this? Right now I instantiate the main window like this:
QQmlApplicationEngine engine; //Actually initialized in the constructor
engine.load(QUrl("qrc:/qml/Window.qml"));
QObject *topLevel = engine.rootObjects().value(0);
QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
I'm using ApplicationWindow (QtQuick Controls) as the main window which is derived from QWindow. I'm open to suggestion here, I'd like to stick to QtQuick and not wrap everything in a standard QWindow or QMainWindow, but maybe that's a poor route to take. Any help would be appreciated.
You can use EventFilter to handle close event in main window's controller:
class MyEventFilter : public QObject
{
Q_OBJECT
protected:
bool eventFilter(QObject *obj, QEvent *event);
};
bool MyEventFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Close)
{
// TODO: confirm
return true;
} else
{
// standard event processing
return QObject::eventFilter(obj, event);
}
}
And in your main():
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
MyEventFilter filter;
QtQuick2ApplicationViewer viewer;
viewer.installEventFilter(&filter);
viewer.setMainQmlFile(QStringLiteral("qml/QCloseConfirm/main.qml"));
viewer.showExpanded();
return app.exec();
}
Here is example. But it doesn't seem to be perfect. There should be a better solution.

QML callback from C++ with custom type as parameter

I would like to be able to call a QML function from C++ with an instance of a custom class as a parameter and then manipulate the instance from QML.
Here is what I did so far :
Data.h
class Data : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)
public :
Data() : QObject(), _text("Foo") { }
virtual ~Data() { }
Data(const Data & other) { _text = other._text; }
QString text() const { return _text; }
void setText(const QString & text) { _text = text; }
private :
QString _text;
};
Q_DECLARE_METATYPE(Data);
Main.cpp
#include "Data.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Data callBackData;
QQmlEngine engine;
QQmlComponent rootComponent(&engine, QUrl::fromLocalFile("CallBack.qml"));
QObject * rootObj = rootComponent.create();
QMetaObject::invokeMethod(rootObj, "callMeBack",
Q_ARG(QVariant, QVariant::fromValue(callBackData)));
return app.exec();
}
CallBack.qml
import QtQuick 2.0
Item {
function callMeBack(data) {
console.log(data.text)
}
}
The console outputs "Undefined". Did I do something wrong ?
When changing the function body to console.log(data) it outputs "QVariant(Data)" so why can't I access the text property of data ?
I tried registering Data as a QML type using qmlRegisterType<Data>(); but this does not change anything.
Try pass a QObject pointer instead:
Data *callbackData = new Data;
...
QMetaObject::invokeMethod(rootObj, "callMeBack",
Q_ARG(QVariant, QVariant::fromValue(callBackData)));
Not tested, but should work (QML recognize QObject* type).