QQuickWidget: grabToImage: item's window is not visible - qt

I'm having a problem when I try to use Item::grabToImage() qml method.
No matter which item I point to, it always says the following error:
grabToImage: item's window is not visible
I tried using the root/toplevel Item named rect too, but it didnt work.
My goal: I want to capture a rectangle sized image with the map tile and polygon draw on it
Below there's a minimal reproducible example
import QtQml 2.2
import QtLocation 5.9
import QtPositioning 5.9
import QtQuick 2.0
import QtQuick.Controls 2.4
Item {
id: rect
width: 1024
height: 768
visible: true
Plugin {
id: mapPlugin
name: "osm"
}
Map {
id: map
enabled: true
visible: true
parent: rect
gesture.enabled: true
anchors.fill: parent
plugin: mapPlugin
zoomLevel: 14
activeMapType: supportedMapTypes[3]
}
Item {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 10
height: 40
Button {
id: saveToDisk
text: qsTr("Pick")
onClicked: {
map.grabToImage(function (result) {
console.log('saving to disk..')
result.saveToFile("pick.png")
})
}
}
}
}
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQuickWidgets/QQuickWidget>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QQuickWidget *q = new QQuickWidget;
q->setResizeMode(QQuickWidget::SizeRootObjectToView);
q->setSource(QUrl("main.qml"));
q->show();
return app.exec();
}

The strategy of QQuickWidget for painting is to create an off-screen QQuickWindow that renders the QML from where a screenshot is taken and drawn onto the widget. The above limits the use of grabToImage() since this method requires that the QQuickWindow of the items be visible.
The solution is to use QQuickView + QWidget::createWindowContainer():
#include <QApplication>
#include <QWidget>
#include <QQuickView>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QQuickView *q = new QQuickView;
q->setResizeMode(QQuickView::SizeRootObjectToView);
q->setSource(QUrl("main.qml"));
QWidget * container = QWidget::createWindowContainer(q);
container->show();
return app.exec();
}

Related

Font stretching in QML

We are converting some older QT widget code to use QML and I cannot find the equivalent property for the QFont::setStretch() operation.
The QML Font page shows only family, bold, italic, underline, pointSize, pixelSize, weight, overline, strikeout, capitalization, letterSpacing, wordSpacing, kerning, preferShaping and hintingPreference.
This font selection is being done within a Text object, along the lines of:
Text {
font.family: "LiberationSans"
font.pixelSize: 178
font.weight: 80
//font.stretch: 75 - doesn't work, no such property
}
Is there no way to set the stretch factor in QML. We're using Qt 5.6 by the way.
Unfortunately this property is not exposed to QML, a possible solution is to use a helper class that receives the QFont, change the stretch and return the new QFont.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QFont>
class FontHelper: public QObject{
Q_OBJECT
public:
using QObject::QObject;
Q_INVOKABLE QFont changeStretchFont(const QFont & font, int factor){
QFont fn(font);
fn.setStretch(factor);
return fn;
}
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
FontHelper helper;
engine.rootContext()->setContextProperty("fontHelper", &helper);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Text {
id: txt
font.family: "Helvetica"
font.pointSize: 13
font.bold: true
text: "hello World"
Component.onCompleted: txt.font = fontHelper.changeStretchFont(txt.font, 200)
}
}
Try this:
Text {
font.family: "LiberationSans"
font.pixelSize: 178
font.weight: 80
transform: Scale { xScale: 0.75}
//font.stretch: 75 - doesn't work, no such property
}

QtQuick StackView loading issues

I'm working through the book "Learn Qt 5" from Nicholas Sherriff.
Now I have some problems getting the QtStackView component to work properly.
I've written following code:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/views/MasterView.qml")));
return app.exec();
}
MasterView.qml
import QtQuick 2.5
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
Window {
visible: true
width: 1024
height: 768
title: qsTr("Client Management")
StackView {
id: contentFrame
initialItem: Qt.resolvedUrl("qrc:/views/SplashView.qml")
}
}
SplashView.qml
import QtQuick 2.5
Rectangle {
anchors.fill: parent
color: "#f04c42"
}
But when executing, the rectangle from SplashView.qml does not appear.
I do not get any errors. If I put the rectangle block inside the window block it works. But even if i put the rectangle with an id in the StackView block it doesn't work.
I'm using an older version of QtQuick than the book recommends, becouse im using not the newest debian distribution.
Am I missing something?
Thanks
The problem is simple, the Rectangle in the SplashView takes the size of the parent:
Rectangle {
anchors.fill: parent //<---
color: "#f04c42"
}
And the parent is the StackView, but the StackView has no size, so the solution is to set a size, for this we can use the anchors:
StackView {
id: contentFrame
anchors.fill: parent // <--- possible solution
initialItem: Qt.resolvedUrl("qrc:/views/SplashView.qml")
}

Run the QtQuick application

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"
}

New qml object added to scene in c++

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.

Qt5 -porting a simple Qt Quick application to Qt5. help needed

I am trying to port a simple Qt Quick application from Qt4.8 to Qt5.0beta.
my initial (Qt4.8) code is similar to what is below:
main.cpp will dipsplay a QDeclarativeView in a frameless window with translucent background
#include <QtGui/QApplication>
#include "qmlapplicationviewer.h"
#include <QtDeclarative>
#include <QDeclarativeContext>
Q_DECL_EXPORT int main(int argc, char *argv[])
{
QScopedPointer<QApplication> app(createApplication(argc, argv));
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qml/main.qml"));
viewer.setWindowFlags(Qt::FramelessWindowHint);
viewer.setAttribute(Qt::WA_TranslucentBackground);
viewer.setStyleSheet("background:transparent;");
viewer.setResizeMode(QDeclarativeView::SizeViewToRootObject);
viewer.showExpanded();
return app->exec();
}
and the main.qml will just display a red rectangle inside another transparent rectangle.
import QtQuick 1.1
Rectangle {
width: 360
height: 360
color: "transparent"
Rectangle
{
x: 125
y: 122
width: 110
height: 116
anchors.centerIn: parent
color: "red"
radius: 27
}
Text {
color: "black"
text: qsTr("Press me!")
font.pointSize: 14
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
}
In order to make it compatible with Qt5 few changes were necessary.
(I have followed http://qt-project.org/doc/qt-5.0/portingqmlapp.html [qt-project.org]
in order not to miss something)
Now main.cpp is similar to:
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QtWidgets/QtWidgets>
#include <QtWidgets/QLabel>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/main.qml"));
viewer.setWindowFlags(Qt::FramelessWindowHint);
viewer.showExpanded();
return app.exec();
}
In main.qml only one line was replaced.
import QtQuick 2.0
but I am not able to find a way of keeping the transparency
setAttribute(Qt::WA_TranslucentBackground);
setStyleSheet("background:transparent;");
setAttribute and setStyleSheet were available for a QDeclarativeView (which is a QWidget)
but not for QQuickView (which is a QWindow)
Try my QuickWidget, if it helps you:
http://code.google.com/p/quickwidget/
Or, even better, use QQuickWidget from Qt 5.3+.

Resources