QML QWidget container - c++

I'm beginning with QML in Qt Creator and I like too much everything I've read about it but now I found a complication.
See following code:
BLCMainWidget::BLCMainWidget(QWidget *parent) : BLCBaseWidgetControler(parent) {
QQuickView view;
view.setSource(QUrl("qrc:///main.qml"));
QWidget *container = QWidget::createWindowContainer(&view);
QHBoxLayout *layout = new QHBoxLayout;
layout->setSpacing(10);
layout->setAlignment(Qt::AlignHCenter);
layout->setContentsMargins(1, 1, 1, 1);
parent->setStyleSheet("background:QColor(200,100,150);");
layout->addWidget(container);
parent->setLayout(layout);
}
Where parent is my QWidget on QMainWindow of my application, but this code not show my QQuickView container. Obviously the parent in question has a setCentralWidget signed in main() method and I'm already using that concept for non-QML widgets perfectly. How can I fix that to show my QML object containers?
My QML is just a simple concept example:
import QtQuick 2.1
Item {
id: box
width: 640
height: 480
Rectangle {
id: redSquare
width: 30; height: 30
anchors.top: parent.top; anchors.left: parent.left; anchors.margins: 10
color: "green"
Text { text: "!"; font.pixelSize: 16; anchors.centerIn: parent }
}
}
Thanks

If you are using a recent version of Qt, QWidget::createWindoContainer is depricated. Create a QQuickWidget instead, and use it a a normal QWidget.

Take a look at this: QML C++ Integration
and this: Interact QML from C++

Related

Is it possible to add a QML item to the window created in mainwindow.ui form? [duplicate]

I am a beginner in QML and try to insert a QML View in QWdiget but I don't understand why it doesn't work.
Here is a simple example of my qml file (this is not the real file):
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQml.Models 2.1
ObjectModel {
id: itemModel
Rectangle {
color: "orange"
anchors.fill: parent
}
Rectangle {
color: "orange"
anchors.fill: parent
}
Rectangle {
color: "orange"
anchors.fill: parent
}
ListView {
id: my_list
anchors.fill: parent
model: itemModel
}
}
And this is how I load it in my mainwindow:
QQuickView *view = new QQuickView();
QWidget *container = QWidget::createWindowContainer(view, this);
container->setMinimumSize(200, 200);
container->setFocusPolicy(Qt::TabFocus);
view->setSource(QUrl("main.qml"));
ui->dockWidget->setWidget(container);
How could I insert my view in a QWidget?
At this time, I really need to use a QML view and because I need to use it in an already existing application, I can't just use a QML project.
Thanks a lot for your help and have a good day!
There exist a special QQuickWidget, dedicated to that exact purpose.
QQuickWidget *view = new QQuickWidget;
view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
view->show();
QQmlApplicationEngine *m_engine in MainWindow.h
in MainWindows.cpp set :
m_engine->addImportPath("qrc:/qml/imports");
m_engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
// m_engine->rootContext()->setContextProperty("mainWindows", this);
qDebug() << "Ok engine created";`
`QWindow *qmlWindow = qobject_cast<QWindow*>(m_engine->rootObjects().at(0));
QWidget *container = QWidget::createWindowContainer(qmlWindow, this);
container->setMinimumSize(200, 200);
container->setMaximumSize(1200, 900);
ui->verticalLayout->addWidget(container);`

How to close a window in QML/Javascript code (with C++ code involved)?

I have a QML window declared for example in MyWindow.qml:
Item {
id: thisWindow
width: 500
height: 140
... sub-items that declare the UI of the window ...
And a C++ class that instantiates that QML:
class MyWindow : public QQuickView
...
MyWindow::MyWindow() {
setSource(QUrl("qrc:/MyWindow.qml"));
setFlags(Qt::WindowFlags(Qt::Popup));
}
How do I close that window from Javascript/QML code?
I can't call thisWindow.close(), because it's just an item type in the hierarchy.
You don't need c++ to do that. You can do it with the window attached property straight from QML.
//other imports
import QtQuick.Window 2.2
Item {
id: thisWindow
width: 500
height: 140
//... sub-items that declare the UI of the window ...
MouseArea {
anchors.fill: parent
onClicked: Window.window.close()
}
}
The easiest option is to export the QQuickView to the .qml with setContextProperty():
#include <QQmlEngine>
#include <QQmlContext>
// ...
{
engine()->rootContext()->setContextProperty("view", this);
setSource(QUrl("qrc:/MyWindow.qml"));
setFlags(Qt::WindowFlags(Qt::Popup));
}
And then in QML you can use:
view.close()
Use the Qt global object and follow the instruction here:
http://doc.qt.io/qt-5/qml-qtqml-qt.html#quit-method

Accessing nested ListView with QQmlContext

I am trying to populate a QML ListView using a class that inherits QAbstractListModel. So far, I managed to create this using the QT Documentation here, under the "QAbstractItemModel subclass" section:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "gamemodel.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
GameModel model; //A class similar to AnimalModel in Qt Documentation.
//It contains a QList of Objects, each having 2 QString
//members (title and genre).
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
model.readFile("c:/somePath/XML_G.xml"); //Initializing GameModel QList member
//using an XML file
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("myModel", &model);
return app.exec();
}
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
Window
{
id: win
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ListView
{
id: myList
width: parent.width
height: 50
clip: true
spacing: 5
orientation: ListView.Horizontal
model: myModel
delegate:
Rectangle
{
width: 150
height: 20
color: "#2255ff"
Text
{
text: gameTitle + " " + genre
}
}
}
}
Up to this point, my code works. However, if I try to change my main.qml file like this:
import QtQuick 2.5
import QtQuick.Window 2.2
Window
{
id: win
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item //ListView is now nested in this Item
{
ListView
{
id: myList
width: parent.width
height: 50
clip: true
spacing: 5
orientation: ListView.Horizontal
model: myModel
delegate:
Rectangle
{
width: 150
height: 20
color: "#2255ff"
Text
{
text: gameTitle + " " + genre
}
}
}
}
}
I end up being unable to set my model using ctxt->setContextProperty("myModel", &model);. From what little I can gather from the Qt Documentation (although I am most likely wrong), QQmlContext acts like a scope for the QML file. Thinking that, I tried changing this:
QQmlContext *ctxt = engine.rootContext();
to this:
QQmlContext *ctxt = engine.rootContext()->findChild<QQmlContext*>("list");
As well as setting my Item's objectName property to "list". Obviously, that failed, and it also caused a crash. Since my experience with QML is limited to the Qt Docs, I have been unsuccessful at finding a workaround. Is a solution using QQmlContext possible, or do I have to use QObject? If so, what would the QObject equivalent of ctxt->setContextProperty("myModel", &model) be?
The first argument of the setContextProperty() call is basically the "identifier" of the object, like the id property on the QML side.
You need to set that before accessing it in QML, otherwise it is unknown at the time of usage.
So you don't need any other call, but you need to do it before you load QML that needs it.
Just move it before the engine.load(...) line in your main.cpp
OK, apparently my problem was in my QML file. In my code, I setup my ListView like this:
width: parent.width
However, when I added an Item as the parent of my ListView, I forgot to set an initial width for my Item, thus turning ListView's width to 0. After I set an initial width for my Item, everything works as expected again.

QML signals connecting

I started writing application in QML (using QtQuick 1.1 with Qt 4.8.1) and I have a few questions about signals. In my project there are following files:
main.qml:
Rectangle {
signal sigExit()
width: 800
height: 600
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
sigExit();
Qt.quit();
}
}
Button
{
x: 10
y: parent.height-height-5
text: "someText"
}
}
Button.qml:
Rectangle {
signal buttonsig()
width: 60
//(...)
MouseArea
{
anchors.fill: parent
onClicked: buttonsig();
}
}
When I want to connect signal from main.qml to C++ slot, I do:
main.cpp :
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qml/MyProject/main.qml"));
viewer.showExpanded();
MyClass* obj = new MyClass;
QObject* item = qobject_cast<QObject*>(viewer.rootObject());
QObject::connect(item, SIGNAL(sigExit()), obj, SLOT(onExitWindow()));
and it works. But what when I want to connect sigbutton() from Button.qml to C++ slot? It will be something like that?
QObject *rect = item->findChild<QObject*>("Button");
QObject::connect(rect, SIGNAL(buttonsig()), obj, SLOT(onExitWindow()));
And the second issue: how can I connect sigbutton() to main.qml (for example, I want to change position of my buttons after clicking them)?
You will also need to have the objectName property of your Button item if you want to access it :
Button {
id: myButton
objectName: "myButton"
x: 10
y: parent.height-height-5
text: "someText"
}
Now you can access it by :
QObject *rect = item->findChild<QObject*>("myButton");
Regarding the second question, you can use Connections object to connect buttonsig() to some QML signal handler in main.qml :
Rectangle {
signal sigExit()
width: 800
height: 600
Connections{
target: myButton
onButtonsig :
{
...
}
}
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
sigExit();
Qt.quit();
}
}
Button
{
id: myButton
x: 10
y: parent.height-height-5
text: "someText"
}
}
Note that the signal handler's name should be on<Signal> (First letter of signal letter Capital). Also Button should have an id to address it in Connections.
Accessing loaded qml elements, casting them and connecting their signals to your C++ slots is perferctly possible. But this method should be avoided in your production code.
See this warning from Qt docs.
So what's the way to call a C++ slot from qml side? You can register the object whose slot needs to be called with qml engine as a context property. Once registered, these context properties can be accessed anywhere from QML side.
Slots of objects registered as context properties can be called directly in your signal handler in QML example: onClicked:{<contextPropertyName>.<slotName>()}
Or, you can connect a QML signal with context property object's slot directly using Connections type. Please see this documentation
For details about registering context properties, please see Embedding C++ objects into QML with context properties.
If you want to see some examples, see my answers to these questions.
Qt Signals and Slots - nothing happens and Setting object type property in QML from C++

Resize Qml window

In my project I created a transparent and frameless QMainWindow, then created QmlApplicationViewer. I need to be able to drag and resize the window.
How can I do?
This app is a small variation of the one presented here to deal with transparent windows in QML applications:
win.cpp:
#include <QApplication>
#include <QDeclarativeView>
#include <QMainWindow>
#include <QDeclarativeContext>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
QDeclarativeView* v = new QDeclarativeView;
window.setCentralWidget(v);
v->setSource(QUrl::fromLocalFile(("draw_rectangles.qml")));
// expose window object to QML
v->rootContext()->setContextProperty("mainwindow",&window);
window.setStyleSheet("background:transparent;");
window.setAttribute(Qt::WA_TranslucentBackground);
window.setWindowFlags(Qt::FramelessWindowHint);
window.show();
app.exec();
}
win.pro:
TEMPLATE += app
QT += gui declarative
SOURCES += win.cpp
draw_rectangles.qml:
import Qt 4.7
Item {
Rectangle {
opacity: 0.5
color: "red"
width: 100; height: 100
MouseArea {
anchors.fill: parent
onPressed: {
mainwindow.size.width = 200;
mainwindow.size.height = 500;
}
}
Rectangle {
color: "blue"
x: 50; y: 50; width: 100; height: 100
MouseArea {
id: mouseRegion
anchors.fill: parent;
property variant clickPos: "1,1"
onPressed: {
clickPos = Qt.point(mouse.x,mouse.y)
}
onPositionChanged: {
var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
mainwindow.pos = Qt.point(mainwindow.pos.x+delta.x,
mainwindow.pos.y+delta.y)
}
}
}
}
}
Even though you are not interested in transparency, this app shows how to expose QMainWindow to QML. This allows the QML application to make changes in the main window.
Click on the blue rectangle to drag the window around, and click on the red rectangle to resize the window using hardcoded values in the qml. Of course, as the window is transparent you won't have the visual feedback of a regular opaque application when you resize it. But the resize operation works, though. Enjoy!