I'm trying to list the items from a QStringList to QML, but I keep getting an undefined error for the bindings.
Here is the C++ code:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QStringList lst;
QString m("item 1");
lst.append(m);
QQmlComponent comp(&engine);
QQmlContext *ctx = engine.rootContext();
ctx->setContextProperty("pLst", QVariant::fromValue(lst));
return app.exec();
}
Here is the QML code:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
id: root; objectName: "root"
title: qsTr("Doesn't Matter")
width: 640
height: 480
visible: true
ListView{
id: lst
model: pLst
}
}
The error says pLst is not defined.
This is because you call load() before you set context property, so pLst does not yet exists at the moment ListView is constructing.
You should call load() after you set the context properties used for initialization of QML objects.
Related
According to http://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html chapter "Invoking QML Methods", I try to invoke the bbox function within main.qml from C++.
Here is my code :
main.qml
import QtQuick 2.0
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6
Window {
width: 512
height: 512
visible: true
Item{
anchors.fill: parent
Plugin{
id: osmplugin
name: "osm"
}
Map {
anchors.fill: parent
id: map
plugin: osmplugin;
zoomLevel: (maximumZoomLevel - minimumZoomLevel)/2
center {
// The Qt Company in Oslo
latitude: 59.9485
longitude: 10.7686
}
}
Component.onCompleted:{
console.log("zoomlevel : " + map.zoomLevel)
console.log("Visible region : " + map.visibleRegion)
}
function bbox(){
return map.visibleRegion;
}
}
}
and main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QGeoRectangle>
#include <QQmlComponent>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QQmlComponent component(&engine, "qrc:/main.qml");
QObject *map = component.create();
QVariant ret;
bool ok = QMetaObject::invokeMethod( map, "bbox", Qt::DirectConnection, Q_RETURN_ARG( QVariant, ret ) );
if ( !ok ){
qWarning( "Fail to call qml method" );
}
QGeoRectangle rect = qvariant_cast<QGeoRectangle>( ret );
return app.exec();
}
I get the following error message :
"QMetaObject::invokeMethod: No such method QQuickWindow::bbox()"
Seems it does not find the bbox function. Could you help me to find the problem ?
Thanks in advance.
Give your item an object name:
Item{
anchors.fill: parent
objectName: "bboxObj"
function bbox(){
return map.visibleRegion;
}
}
In C++ get your Object using the object name:
QObject *map = component.create();
QObject *bboxObj= map->findChild<QObject*>("bboxObj");
and invoke the method:
if (bboxObj)
ok = QMetaObject::invokeMethod( bboxObj, "bbox", Qt::DirectConnection, Q_RETURN_ARG( QVariant, ret ) );
I create a project on QtQuick in QT Creator 4.3.1 without using the ui form.
Here's the code main.qml:
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MouseArea {
anchors.fill: parent
onClicked: {
console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"'))
}
}
TextEdit {
id: textEdit
text: qsTr("Enter some text...")
verticalAlignment: Text.AlignVCenter
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
Rectangle {
anchors.fill: parent
anchors.margins: -10
color: "transparent"
border.width: 1
}
}
}
The program runs and works.
Now I want to get rid of Window and replace it with Rectangle:
import QtQuick 2.6
Rectangle {
id: root
width: 200; height: 200;
color: "#ffffff"
}
But when the program starts, nothing happens, the form does not open
What am I doing wrong?
main.cpp code. code in the same in both cases:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
In a Qt application you must have at least one window that is the top-level, that is, the window where other components are placed.
When you create your project, you should get the default main.cpp:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
}
So let's analyze the elements and use the documentation for it:
QQmlApplicationEngine:
QQmlApplicationEngine provides a convenient way to load an application from a single QML file.
[...]
Unlike QQuickView, QQmlApplicationEngine does not automatically create a root window. If you are using visual items from Qt Quick, you will need to place them inside of a Window.
That is, QQmlApplicationEngine does not create a top-level, so if we want the window to be shown you must use another element, and as recommended, an option is to use Window{}
In your second test you are using an item, e.g. Rectangle, and this is only a component and is not able to create a top-level, so for that it is advisable to use QQuickView:
The QQuickView class provides a window for displaying a Qt Quick user interface.
[...]
So if you want to show the Rectangle you should use the following in your main.cpp:
main.cpp
#include <QGuiApplication>
#include <QQuickView>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.show();
return app.exec();
}
main.qml
import QtQuick 2.6
Rectangle {
id: root
width: 200; height: 200;
color: "#ffffff"
}
I have defined a QML object under MyQMLObject.qml. This QML file looks like this:
import QtQuick 2.4
Item {
id: rootItem
implicitWidth: LayoutUtils.maxImplicitWidth(children)
implicitHeight: LayoutUtils.maxImplicitHeight(children)
Text {
id: text1
}
Text {
id: text2
}
// ...
Text {
id: textN
}
}
The text is added dynamically when the application starts. For each language different text is added, there for the width of the rootItem varies by the chosen language. I would like to somehow create MyQMLObject only once at application startup without even visualizing it and save its actual width in a singleton for example so I can reuse that value throughout my code without creating MyQMLObject more then once. How could I achieve this?
Right now I have a singleton QML file, which holds a QtObject which contains some constant values. Can I somehow create an instance of MyQMLObject within this singleton QtObject?
My singleton Style.qml looks like this:
pragma Singleton
import QtQuick 2.4
QtObject {
readonly property int maxWidth: 400
// ...
}
Firstly, if possible, you could use a Column instead of manually calculating the maximum width:
MyQMLObject.qml
import QtQuick 2.4
Column {
Text {
text: "blah"
}
Text {
text: "blahblah"
}
}
You can use dynamic object creation to create the temporary Column item:
Style.qml
pragma Singleton
import QtQuick 2.4
QtObject {
readonly property int maxWidth: {
var component = Qt.createComponent("qrc:/MyQMLObject.qml");
if (component.status === Component.Error) {
console.error(component.errorString());
return 0;
}
return component.createObject().width;
}
}
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import App 1.0
Window {
visible: true
Component.onCompleted: print(Style.maxWidth)
}
Then, register the singleton:
main.cpp
#include <QtGui>
#include <QtQml>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterSingletonType(QUrl("qrc:///Style.qml"), "App", 1, 0, "Style");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
However, note that this approach could be improved by calculating the maximum width from C++, eliminating the need to construct an item only to throw it away. Working off this example:
#include <QtGui>
#include <QtQml>
class Style : public QObject
{
Q_OBJECT
Q_PROPERTY(int maxWidth READ maxWidth CONSTANT)
public:
Style(QObject* parent = 0) :
QObject(parent),
mMaxWidth(0)
{
QFontMetrics fontMetrics(qApp->font());
// Here is where you'd fetch the text...
QStringList dummyText;
dummyText << "blah" << "blahblah";
foreach (const QString &string, dummyText) {
const int width = fontMetrics.boundingRect(string).width();
if (width > mMaxWidth)
mMaxWidth = width;
}
}
int maxWidth() const
{
return mMaxWidth;
}
private:
int mMaxWidth;
};
static QObject *singletonTypeProvider(QQmlEngine *, QJSEngine *)
{
Style *style = new Style();
return style;
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterSingletonType<Style>("App", 1, 0, "Style", singletonTypeProvider);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
#include "main.moc"
It uses QFontMetrics to calculate the width.
main.qml remains unchanged.
I have a problem with adding new QML object to existing scene.
My main.qml source:
ApplicationWindow
{
id:background
visible: true
width: 640
height: 480
}
MyItem.qml source:
Rectangle
{
width: 100
height: 62
color: "red"
anchors.centerIn: parent
}
Finally, here is my main.cpp source:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQmlComponent *component = new QQmlComponent(&engine);
component->loadUrl(QUrl("qrc:/MyItem.qml"));
qDebug() << "component.status(): "<< component->status();
QObject *dynamicObject = component->create();
if (dynamicObject == NULL) {
qDebug()<<"error: "<<component->errorString();;
}
return app.exec();
}
main.qml appears correctly but MyItem.qml doesn't appear inside main.qml. Component.status() returns state Ready, no errors on dynamicObject. What am I doing wrong?
You need to specify a parent for the item otherwise it isn't a part of the visual hierarchy and won't be rendered.
I think you should use QQuickView instead of QQmlEngine. main.cpp would be:
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
view.show();
QQmlComponent component(view.engine(), QUrl("qrc:/MyItem.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
item->setParentItem(view.rootObject());
QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
return app.exec();
}
And you need to change main.qml type from ApplicationWindow to Item
Item
{
id:background
visible: true
width: 640
height: 480
}
It is easier, and this way you can create a class that extends QQuickView and which manages the creation of your new items.
dose anyone know how to convert Qt::WidgetAttribute to Qt::WindowFlags???
and by convert i mean is there any WidgetAttribute like WA_NoBackground or WA_TranslucentBackground as a flag for WindowFlags....???
i've been trying to transparent my ApplicationWindow Item in QML but i couldn't.
Main.Qml
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Window 2.0
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
flags: Qt.SubWindow | Qt.Tool | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
opacity: 0.5
Image {
anchors.fill: parent
source: "blah.png" // and this picture in transparent
}
}
and know im looking for the flag that works like WA_NoBackground and WA_TranslucentBackground
Main.cpp
int main(int argc, char *argv[])
{
Application app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl("blah.qml"));
QObject *topLevel = engine.rootObjects().value(0);
QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
window->show();
window->setColor(Qt::transparent);
return app.exec();
}