Right way to dynamically create qml windows - qt

I'm working on a Qt application and I need to create windows dynamically. Each window consists of QObject-based c++ backend and qml-based interface. Each window needs to be connected to the bunch of signals emitted by core classes.
Current solution is to derive window from QQuickView, connect signals to it and load qml using setSource(). Is it a right way or there is a better way?
Is it better to use one QQmlEngine for all windows (and use this engine as parent for every window) or create new engine for each new window?

For this I would expose a c++ model to the QML code.
Since this model would be dynamic (elements can be added or removed), I'd use a QAbstractItemModel derived model that can inform the views that some elements are added/removed. Using something else like a QList<QObject*> would mean that you'd have to tell the view that the entire model should be reloaded after each change.
Instead of implementing the model from scratch, you could use a class like QQmlObjectListModel from Qt QML Tricks, it exposes a QList-like API from c++ but is a QAbstractItemModel exposing the QObject properties as roles under the scene.
Another solution that you could use if you don't want to use QObjects is benlau's QSyncable (I've actually used this in a similar situation to yours, where I expose my screens in a model and instantiate a Window displaying a taskbar for each).
Then, I'd use a QQmlApplicationEngine and expose the model to it with setContextProperty. A QQuickView is already a window, so I don't think you want to use that, better to manage your windows manually in the QML code.
Then in your QML code, use an Instantiator as your root object, set your model, and use Window as its delegate :
Instantiator {
model: yourModel
Window {
/* ... */
}
}

Related

Pass arguments to constructor of widget within QStackedWidget

I have a graphical application written in C++ using Qt for an embedded device, which uses a QStackedWidget holding a number of UI widgets. The UI is all designed in Qt Creator's designer tool. When the user navigates through the device's application the display to be shown at that menu option is selected from the QStackedWidget and this all works great.
I'm now wanting to pass in a pointer to some configuration which is read from file when the application starts, but I can't seem to find a way to pass this pointer as an argument into the constructor of a widget on the QStackedWidget. Can anyone help?
My current approach is to call a function I've written within the class of a widget on the QStackedWidget, which works but doesn't feel the best way to do it.
To my knowledge if you want to use custom constructors - with other kinds of arguments than just the QWidget * parent - you have to create the ui programmatically:
create your custom StackedWidget with a special constructor,
prepare the global interface using the designer,
then add the StackedWidget in the constructor of the class after the setupUi method.
The other way is to use an initialization method after the construction of the item, like you did.

QFileDialog in a non-QT app

I have an app that uses a 3rd party GUI framework, but I want to open files with using QFileDialog. I'm thinking of instantiating a subclass of QWidget that is invisible and serves the purpose of serving up the dialog.
Is there a better way to do this?
I don't see any need for an invisible widget, since the file dialog doesn't require a a parent widget in order to be shown up.
Since the dialog needs to have a Qt event loop running, you will need to either show the dialog modally using exec(), or using one of the static functions like getOpenFileName.
To use any of the widget classes, including the file dialog, you need to have an instance of QApplication, although that instance doesn't have to have its exec() method called.

OpenGL rendering to a QML item

I have a QML file which contains a layout of QML items and now I want one of those items to be a QGLWidget. i.e. I want to render to a specific QML item.
Is anyone aware of how to do this?
The simplest way I suppose it to provide QML a new custom component implemented in C++. I couldn't find anything ready.
You could subclass the QDeclarativeItem and implement your OpenGL code in the paint function after using the QPainter::beginNative() function. After that you can "export" your new custom item to QML this way. This is quite simple and should work, but you'll have to setup the viewport of you QDeclarativeView to be a QGLWidget, something like this:
QDeclarativeView view;
// This is needed because OpenGL viewport doesn't support partial updates.
view.setViewportUpdateMode(QGraphicsView::FullViewportUpdateMode);
view.setViewport(new QGLWidget);
or you'll have to use the opengl graphics system for the entire application.
Another way is using QML/3D.
This thread will give you some other information.

Qt: How to initialize dialog widgets?

I would like to know what the established procedure is for initializing the controls within a Qt custom dialog box. In the code I am writing, the dialog would present a QListView containing directories from an object passed (by reference) to the dialog class during construction. When the dialog is displayed, I obviously want the list to display the directories currently configured in the object.
Where should this be done though? Perhaps in the overridden showEvent() method?
Background: I used to do a lot of MFC programming back in the day, and would have done this sort of stuff in the OnCreate method, or some such, once the window object had been created.
Thankfully Qt doesn't require you to do any hooking to find the moment to create things (unless you want to). If you look over the Qt examples for dialogs, most do all the constructing in the constructor:
http://doc.qt.io/archives/qt-4.7/examples-dialogs.html
The tab dialog example--for instance--doesn't do "on-demand" initializing of tabs. Although you could wire something up via the currentChanged signal:
http://doc.qt.io/archives/qt-4.7/qtabwidget.html#currentChanged
Wizard-style dialogs have initializePage and cleanupPage methods:
http://doc.qt.io/archives/qt-4.7/qwizardpage.html#initializePage
http://doc.qt.io/archives/qt-4.7/qwizardpage.html#cleanupPage
But by and large, you can just use the constructor. I guess the main exception would be if find yourself allocating the dialog at a much earlier time from when you actually display it (via exec), and you don't want to bear the performance burden for some part of that until it's actually shown. Such cases should be rare and probably the easiest thing to do is just add your own function that you call (like finalizeCreationBeforeExec).

Is it possible to declare a QWidget as a child of a window created outside of Qt?

I'd like to use Qt in my browser plugin, but I don't get to create my own window, the browser does.
What I'd like to do is create a QWidget as a child of a native window handle... Is this possible?
You may be able to take over a native window handle by calling QWidget::create() in your custom widget's constructor. Note that it's a protected method so you can't call it on a normal QWidget.
If you're using a dialog and not an embedded window it's relatively easy. Call QWidget::winId() on your top-level widget. In Qt4 this will return a WId, which is a preprocessor definition for HWND. In Qt5, WId is a typedef for HWND, so you have to perform an explicit cast:
HWND hwnd = (HWND)widget->winId()
Unfortunately, the functionality in Qt5 is currently unreliable/partially broken. As of Qt 5.4.1, it's not resolved and there's a note in the source that QWidget::winId() is "going away". note that this issue primarily affects embedded native windows in a Qt app, not vice versa. Your mileage may be better.
Note: QWidget::create() is intended for embedding native windows in Qt. It probably does not apply in your situation.
Only if you can cast it as a QWidget.

Resources