Qt Quick / QML flag changes in C++ back to UI - c++

I'm familiar with Qt from some time back, but I could use a little guidence with QML/QTQuick interactions with C++. I feel I'm missing something simple here, but am a little stuck.
I'm developing an embedded system displays the status of distributed switches communicating on a serial bus. The serial bus runs as a separate thread in C++ (has always been Qt) and automatically polls devices in a round robin fashion to get updates from the devices.
Looking into this, I found a pretty simple example using QAbstractList model to share the status via QML properties from the backed C++. https://www.youtube.com/watch?v=9BcAYDlpuT8&list=PLo12gBvZwC78nnrZHCBowKf36ZAi7iOLW&index=4&t=0s
Initially the model looked great, I simply loaded a list with the information I needed and can see it from the UI. The question is, how do I access the model from C++ to have updates bubble up to the UI when they change in the background.
What I've done so far:
Register model:
qmlReisterType<ModelDerrivedClass>("DeviceListModel",1,0,"DeviceList")
Define roles:
enum {
OpenRole = Qt::UserRole,
StatusRole
}
Define Hash table for model
QHash<int,QByteArray> ModelDerrivedClass::roleNames() const
{
QHash<int, QByteArray> names;
names[OpenRole] = "openstatus";
names[StatusRole] = "devicestatus";
return names;
}
Create simple list of structures with the proper information, implent then necessary methods, etc...works like a charm from top down.
How do I access the model from the bottom up? These devices will update status according to external input the UI doesn't need to be aware of, but these events need to be able to drive the front end. It almost looks like this scenario isn't accounted for.
I've also looked into registering a device type with QML, but can't figure out how to link a QML object to a C++ object so the the READ/WRITE/NOTIFY properties work with individual QML objects in a list. In this scenario, I would register OPEN and STATUS as properties of a QML type that could be used in the QML code directly, but I would need to associate the object instance int C++ with the QML object instance. This is something the QAbstractListModel appers to work around.
Any assistance would be appreciated.

You have two options, but I think the first is the better:
option 1: rootContext
You can set a property on the rootContext of a QQMlEngine, which will be available throughout every QML file loaded by that qml engine (see Qt docs):
QQuickView view;
view.rootContext()->setContextProperty("currentDateTime",
QDateTime::currentDateTime());
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
You should have an instance of the model:
ModelDerivedClass devices;
QQuickView view;
view.rootContext()->setContextProperty("devices", &devices);
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
You can now make changes to the ModelDerivedClass using setData or your own methods.
BTW, in this option you should not register as type, but as uncreatable type:
qmlRegisterUncreatableType<ModelDerrivedClass>("DeviceListModel",1,0,"DeviceList", "available as rootContext property 'devices'");
Option 2: singleton
You can make the ModelDerivedClass a Singleton, which is only available once. Add an instance function to the class:
class ModelDerivedClass
{
...
ModelDerivedClass* instance() {
static ModelDerivedClass theInstance;
return &theInstance;
}
...
}
From C++ you can use ModelDerivedClass::instance() to operate the changes.
You should also register it to QML as singleton:
qmlRegisterSingletonType<ModelDerivedClass>("DeviceListModel", 1, 0, "DeviceList",
[](QQmlEngine *eng, QJSEngine *js) -> QObject*
{
return ModelDerivedClass::instance();
});
But in this case you don't have much control over the lifetime of the object, which is arguably not good (lots of discussion can be found on this subject). So I would advice to take option 1.

The main thing to realize is that your main thread is a special thread that must be the only thread that accesses and changes anything about your GUI state. Most everything about Qt GUI and QML is single threaded.
Therefore, you'll want to communicate the change from your serial bus thread over to the main thread. This can be done connecting a slot/signal from the serial bus thread to an appropriate object on the main thread.
Qt knows when you've crossed thread boundaries with a connection like that and will post it in a way to the main thread that ensures it gets handled in a single-threaded fashion.

Related

Qt / CPP: how to implement callbacks with signals and slots the "right way"

I'm trying to implement an application in Qt with a model-view-controller scheme. I have some model classes (databases), one application controller, and a bunch of GUI classes. All GUI classes know the app controller and can call its public slots to send data to it that should be stored in the model. The app controller takes the data and calls the appropriate database to store it. The database classes check the data and return a bool to the app controller to tell if the data was okay or not.
Now, one GUI element has prepared some user data and wants to send it to the app controller. I am trying to figure out how to let the GUI-class know that the app controller validated the incoming data with the model and it accepted the data. My app controller shouldn't care nor know which GUI elements call its public API to commit data to the model. But how does the app controller communicate a response to the GUI element to tell it, that everything was fine, so the GUI element can close itself?
My idea would have been to let the GUI element create a random number token to send it to the app controller together with the data as a kind of "callback address". As soon as my GUI element receives an okay signal with the correct token attached, it can react to that.
I was dunno. All my solutions feel weird and not how it's supposed to be in Qt.
Edit 1: a pseudo-code example for clarification:
void Appcontroller::Slot(userdata)
{
bool okay = database->save(userdata)
};
void Appcontroller::CreateMasterWindow()
{
this->masterwindow_ = new MasterWindow(this);
// I am propagating the knowledge of the app controller to the
// MasterWindow and the latter can propagate that info further
// down, that's fine (everybody can know the responsible
// controller, but I don't think the controller should care about
// all his bastard children)
};
void MasterWindow::CreateSubWindow()
{
this->subwindow_ = new SubWindow(appcontroller_);
// the masterwindow creates a random subwindow that the controller
// should't have to care about
};
void SubWindow::SendUserData(userdata)
{
QObject::connect(this, &SubWindow::SendToControllerSignal,
appcontroller_, &Appcontroller::Slot);
emit SendToControllerSignal(userdata);
// how to get a callback (targeted to me/this) from this,
// if the appcontroller does not know me? what is de way?
};
TL;DR: Connections should be made outside of the components. To compose the parts of your system, you instantiate the objects, and then connect them for desired functionality. The objects should otherwise have no knowledge of each other.
Thus, the only means of communication between the objects are signals and slots.
All GUI classes know the app controller and can call its public slots to send data to it that should be stored in the model
Nope.
The GUI classes should know nothing. When a GUI class needs something, it emits a signal. When a GUI class is supposed act on something (e.g. a change in the model), it exposes that as a slot.
I am propagating the knowledge of the app controller to the MasterWindow
Why? The MasterWindow exposes its functionality via signals and slots. Composing it into a bigger system is accomplished by signal/slot connections. No other knowledge is needed.
The app controller takes the data and calls the appropriate database to store it.
Does there even need to be a controller? All it seems to do is act like a signal-slot connection. You can directly connect the GUI classes to the database, and the controller could be what sets the connections up initially.
Otherwise, the application controller can act as a viewmodel, i.e. a QAbstractItemModel that adapts the model exposed by the database, and tweaks it for display/interaction (e.g. adds color properties, icons, etc.).
The database classes check the data and return a bool to the app controller to tell if the data was okay or not.
The database classes should expose slots that are used to modify the database state. They should also expose signals that indicate any changes. To indicate failure, the database can indicate a "change" with the same value.
how to get a callback (targeted to me/this) from this, if the appcontroller does not know me? what is de way?
The signals from the model/database are connected to the GUI classes. A GUI class can go into a "change pending" state once it emits a "change requested" signal. It will then react accordingly when its "new value" slot is called with the updated value: if the value didn't change, it indicates a failure, otherwise it indicates success. If it didn't request a change, it simply updates the displayed value - something else changed it.
This can be all done using nothing more than the Q_PROPERTY mechanism, and the change notification signals.
If the values aren't simple discretes, but rather have some structure, expose those as indices in a custom QAbstractItemModel. Each GUI item can then act on one or more model indices: requesting the changes, and reacting to value updates.
Multiple GUI elements can be hooked up to the same database variable (or no GUI elements!), and the GUI must support this and update its state to reflect the state of the model.
The "tickets" or "request identifiers" you propose are mostly spurious. The requesting GUI element has enough state to know that it requested a change, and can always act predictably on subsequent feedback from the model/database.

Several windows as a single taskbar icon

Currently I am writing a C++ Qt GUI standard (i.e. via Qt Creator) application.
Basically, what I am trying to do is an application, which operates the following singleton classes:
a MainWindow class, which is responsible for the core logic;
a ServerWindow class, which is responsible for the server connection;
a User class, which is returned (in form of a pointer) by the ServerWindow class after successfull authentication;
a Data class, which is initialized with the data, recieved via ServerWindow upon user authentication.
The algorithm is:
Construct a MainWindow and create a Data class; it also holds a pointer (nullptr at this step) at the current user.
When the constructor has finished, the ServerWindow (derived from QDialog) is executed (via Qt delayed connection). At this step the MainWindow is frozen and set invisible, untill the ServerWindow emits one of the signals (logged, fail). The ServerWindow has a modal mode flag set.
When the ServerWindow is done, a pointer to the current user is passed to the MainWindow. The ServerWindow also knows about the Data class and initializes it.
The main problem is that at step 2 the application icon in the taskbar (I use Windows OS) is not shown. When the MainWindow is "offline" (i.e., not shown, invisible via setVisibility(false)), there is no icon. It is highly annoying, especially if there is a bunch of other applications open. So that, my question is: what can I do to make ServerWindow create an application icon in the taskbar without MainWindow being shown?
The additional, by-the-way question is about possible application architecture remastering. I cannot find any books in my small library about similar applications designing. Frankly, I cannot even figure out, which words I should pass to the Google search line. Any advice?
Preliminary, thanks for any answers!

c++ application save and apply preference pattern (may be boost or something)

Typical situation: you have an application, that save and load preferences
(save and load handled by class Config).
Imagine there's such a preference for fonts of some GUI elements.
So we have
struct Font;
struct Config {
const Font& getFontForSpecificGUIElement() const;
//save to disk if Font changed
void setFontForSpecificGUIElement(Font);
};
Whenever the font is changed I need to inform all instances of class SpecificGUIElement of that change.
How can achieve such notification functionality?
To keep Config simple I want to decouple that functionality. Besides, there will many properties like this (30-50 of them).
So in general I want:
Not require implementing virtual interfaces
I don't need thread safety
Convenient registration of event handlers
I need notification for new subscribed receivers, with last recent
notification if were any (I mean, as in my example Font changed, and when new GUI elements subscribe on such event, they receive, event automatically triggered for them, and they receive last variant of Font)
Convenient registration of event type (I mean in item above
we create some kind of value cache, so it should be simple add new one)
I suppose this is common enough requirements, so may be there already solution,
in popular C++ libraries, like boost ?
Update:
Why Qt not suitable for me. I see two approaches
with Qt, QEvent subsystem. But because of it is impossible
send event to unknown listeners it is no go. Why not signal/slots, first you need inherit QObject, second to implement (4), I have to create MessageBus class to cache last values, and adding new events starts require to much work:
add data field, add new signal, add function(X) to emit new signal, because of signal actually protected functions,
plus in (X) i need compare last value with new one.
Yes, this alsready exists in e.g.:
Boost Signals2
http://www.boost.org/doc/libs/1_59_0/doc/html/signals2.html
There are many samples that should get you going.
Signals2 does offer thread safety, but I guess that doesn't harm.
Alternatively,
Qt
Qt does have a signals/slots implementation, as do many other UI frameworks:
http://doc.qt.io/qt-4.8/signalsandslots.html

qml c++ property bindings with multiple threads

I am creating an modular application. It has a Core, and a few modules, amongs which is a gui module. These modules can be started via the command line:
myApp gui=qml=qmlFile.qml connection=serial=/dev/ttyS1
will start the app with one (multiple is also possible) gui and one serial connection. There is always one Router object, which handles the connection. Guis are loaded by a class that looks like this:
class Gui :QObject{
Core* core;
public:
QQmlApplicationEngine engine;
public slots:
void start(){
engine.load("qrc:/gui/from/command/line.qml");
}
In the gui i have a nice bit of qml called ConnectionController{} which is an easy way of adding/removing connections. But this is only the first of it's kind: in the end every module should have a qml component for controlling it.
This all works fine, but now i am trying to add multiple threads. I want to have a RouterThread and a GuiThread. This in itself was simply a matter of changing the creation of the Router (by the Core) to this:
m_router = new Router(this /*not as parent, just as pointer*/);
m_router->moveToThread(&routerThread);
(gui's still live in the main thread for now)
After this everything still works fine, except for qml property bindings.
QQmlEngine: Illegal attempt to connect to SerialConnection(0x7f58d00013a0) that is in a different thread than the QML engine
Because Gui and it's child QQmlEngine engine live in the guiThread while the SerialConnection lives in the routerThread.
Signals and slots between Router and Gui (without qml) do work, because they are handled by default as asynchronous by qt. (as long as the appropriate types are defined.)
Well, no, you cant access threaded objects from your gui and should not try to either.
You need to build a c++ model that lives in the main thread that is exposed to qml. Inside this model you can connect to signals emitted by your threads via a queuedconnection and link them to the models' own signals.
Also you should make sure that when you read data from an object owned by another thread, everything is properly mutexed or you will be reading garbage.

Is there an equivalent to MFCs OnUpdate in Qt?

I have an existing application that uses MFC for the UI, and I'm trying to migrate to Qt. For the most part the migration is straight forward, but I'm not sure how to manage the enabled state of actions (menu and toolbar items).
In MFC you implement a callback with enable/disable logic, and this is called when the item is displayed. In Qt, you only have access to the setEnabled() method.
Is there a built-in or standardized way of connecting an update callback to an action? or do I need to create my solution using timers and registering actions with it? In a large application such as the one I'm working with, the 'should enable' logic can jump all over the place - i.e. certain files on disk must exist, the main display must have a selection, the application's ProcessManager::isProcessing() must be false, etc. It doesn't seem practical to rely on setEnabled() being called on specific actions when there are so many conditions behind the enable/disable logic.
The most "standard" Qt way would be the use of signals/slots.
In my MDI apps, which are based on the Qt MainWindow/MDI examples, I just connect a single "updateMenus()" function to the signal emitted whenever an MDI subwindow is shown or hidden.
Now that may not be enough granularity for your application. So what you could do is - still have a single "updateMenus()" method - but connect it to each menu's "aboutToShow()/aboutToHide()" signals.
That way you keep the logic from sprawling all over the place, and only update menus right when they are needed (like in MFC's OnCmdUI()).
Here's my mainwindow constructor:
mp_mdiArea = new QMdiArea();
setCentralWidget(mp_mdiArea);
connect(mp_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(updateMenus()));
And here's my updateMenus():
void MainWindow::updateMenus()
{
bool hasMdiChild = (activeMdiChild() != nullptr);
mp_actionSave->setEnabled(hasMdiChild);
mp_actionSaveAs->setEnabled(hasMdiChild);
mp_actionClose->setEnabled(hasMdiChild);
}
See Qt 4.8 doc for menu->aboutToShow()/Hide() here