QtQuick StackView loading issues - qt

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

Related

Showing a popup without any toplevel window in QtQuick

I want to make a game overlay to show my custom cross-hair. I want it to be always there with no closing policy.
I used a Popup item in an ApplicationWindow and I set the opacity of it to 0 and the opacity of the pop-up to 1 but it just showed me nothing.I also tried using the pop-up item without any toplevel window but again nothing.
The question is "Is it possible to show an always-on-top popup without any visible top-level window ?"
Your suggestions would be appreciated.
Without a popup window, we can try out with the 'z' property of the QQuickItem. Stack the crosshair always on top of your other items. And if you want to move the crosshair across the screen you can use their 'x,y' properties.
I have tried a simple sample for the same. Used an Image item for crosshair on top of the scroll view. It works as expected. I tried my way. We will see if some other idea's coming in.
Sample code here:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
width: 640
height: 480
// used here only to indicate image loading is going on
BusyIndicator {
id: busyindicatorId
visible: backgroundImgId.status === Image.Loading ||
crossImgId.status === Image.Loading
anchors.centerIn: parent
}
// background item
ScrollView {
anchors.fill: parent
anchors.margins: 10
clip: true
visible: !busyindicatorId.visible
Image {
id: backgroundImgId
source: "https://i.ibb.co/ZBNLvzb/andriod.jpg"
}
}
// crosshair item
Image {
id: crossImgId
z: 1
width: 100
height: width
visible: !busyindicatorId.visible
source: "https://i.ibb.co/SJFTLwN/cross.png"
anchors.centerIn: parent
}
}
Updates
Instantiated two windows of that one can be used for crosshair and have to set some window properties(transparent, alwaysontop) to show always on top. Let's have a look at this base code. Sample video
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QScreen>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QScreen *screen = QGuiApplication::primaryScreen();
QQuickView view;
view.setSource(QUrl(QStringLiteral("qrc:/crosshair.qml")));
view.setX(screen->geometry().width()/2 - view.width()/2);
view.setY(screen->geometry().height()/2 - view.height()/2);
view.setColor("transparent");
view.setFlags(Qt::SubWindow | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
view.show();
return app.exec();
}
//////////////// main.qml ////////////////
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
visibility: "FullScreen"
objectName: "mainWindow"
// used here only to indicate image loading is going on
BusyIndicator {
id: busyindicatorId
visible: backgroundImgId.status === Image.Loading
anchors.centerIn: parent
}
// background item
ScrollView {
anchors.fill: parent
anchors.margins: 10
clip: true
visible: !busyindicatorId.visible
Image {
id: backgroundImgId
source: "https://i.ibb.co/ZBNLvzb/andriod.jpg"
}
}
}
//////////////// crosshair.qml ////////////////
import QtQuick 2.9
import QtQuick.Controls 2.2
Item {
width: 100
height: 100
// crosshair item
Image {
width: parent.width
height: parent.height
source: "https://i.ibb.co/SJFTLwN/cross.png"
}
}

QQuickWidget: grabToImage: item's window is not visible

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();
}

Issue with Material Style in QML

I have this small example that does not work as i expected :
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2
Window {
id: root
visible: true
width: 640
height: 480
property bool lightTheme: false
Material.theme: Material.Dark
Material.foreground: Material.color(Material.Red) // value is always material red #F44336 (from light theme)
onLightThemeChanged: {
Material.theme = lightTheme ? Material.Light : Material.Dark;
}
Button {
id: btn
width: 200
height: 200
anchors.centerIn: parent
text: "change theme"
onClicked: {
lightTheme = !lightTheme;
}
}
Text {
id: darkRed
text: "predefinedDarkThemeRed"
color: "#EF9A9A"
anchors.top: btn.bottom
anchors.horizontalCenter: btn.horizontalCenter
}
Text {
id: lightRed
text: "predefinedLightThemeRed"
color: "#F44336"
anchors.top: darkRed.bottom
anchors.left: darkRed.left
}
}
The issue is with the default Material.Red color being always picked from the Material.Light theme whatever theme i have selected.
However, when i don't set any Material.foreground, then it is white with the Material.Dark and dark with the Material.Light, and dynamically switched between those colors when the theme is changed, so everything is fine.
I would expected the same behaviour with a custom Material.foreground but it does not seem to work.
What is wrong here ?
Thank you.
Note: the app is run with options -style material args, and i am using Qt 5.9.3 or Qt 5.10.1
i think you missed a little nuance
add in .pro file
QT += quickcontrols2
in mine file add QQuickStyle::setStyle("Material");
#include <QQuickStyle>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
................
QQuickStyle::setStyle("Material");
//The style can also be specified as a path to a custom style, such as
//QQuickStyle::setStyle(":/mystyle");
................
return app.exec();
}
in your example, the result will be
when pressed

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

Qml QTouchDevice

I am new in Qt. I am working on windows desktop application and using Qt with qml. On PC that hasn't QTouchDevices, splitter between component (element that allow you resize component on window) works good with mouse (screenshot "Good distance"), but if screen is touchscreen I have next problem, please look on screenshot "Wrong distance".
My application shouldn't support any touch device. So how to disable this Qt feature? I need the same behavior like on device without touch screen.
Wrong distance
Good distance
I have tried disable touch device using privet methods using next sample:
QWindowSystemInterface::unregisterTouchDevice(QTouchDevice::devices().first());
This works, but QWindowSystemInterface is private class and it disable touchscreen. And one more in QTCreator splitters work fine, exactly as I need.
If you can't patch Qt, the only way that I can think of would be to iterate through the children, searching for the MouseArea. For example, suppose you had this QML:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
width: 600
height: 400
visible: true
property alias splitView: splitView
SplitView {
id: splitView
anchors.fill: parent
Rectangle {
width: 200
Layout.maximumWidth: 400
color: "lightblue"
Text {
text: "View 1"
anchors.centerIn: parent
}
}
Rectangle {
id: centerItem
Layout.minimumWidth: 50
Layout.fillWidth: true
color: "lightgray"
Text {
text: "View 2"
anchors.centerIn: parent
}
}
}
}
You could then print out the object tree of the SplitView like so:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QDebug>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QObject *window = engine.rootObjects().first();
QQuickItem *splitView = window->property("splitView").value<QQuickItem*>();
splitView->dumpObjectTree();
return app.exec();
}
That gives you:
SplitView_QMLTYPE_1::
QQmlComponent::
QQuickSystemPalette::
QObject_QML_2::
QQmlComponent::
QQuickItem::
QQuickItem::
QQuickItem::
QQuickLoader_QML_3::
QObject_QML_4::
QQuickMouseArea_QML_5::
QQuickRectangle::
QQmlContext::
QQuickItem::
QQmlComponentAttached::
QQuickRectangle::
QQuickText::
QQuickLayoutAttached::
QQuickRectangle::
QQuickText::
QQuickLayoutAttached::
QQuickLayoutAttached::
QObject::dumpObjectTree() prints out metaObject->className(), so we know to look for an object whose metaObject has a className matching that:
Then:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QScreen>
#include <QWindow>
#include <QDebug>
QQuickItem *findMouseArea(QQuickItem *item)
{
foreach (QQuickItem *childItem, item->childItems()) {
if (QString(childItem->metaObject()->className()).startsWith(QStringLiteral("QQuickMouseArea_QML"))) {
return childItem;
} else {
QQuickItem *mouseArea = findMouseArea(childItem);
if (mouseArea) {
return mouseArea;
}
}
}
return 0;
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QWindow *window = qobject_cast<QWindow*>(engine.rootObjects().first());
QQuickItem *splitView = window->property("splitView").value<QQuickItem*>();
QQuickItem *mouseArea = findMouseArea(splitView);
mouseArea->setProperty("defaultMargin", QVariant(window->screen()->physicalDotsPerInch() / 25.4));
return app.exec();
}
Apparently, Screen::pixelDensity is calculated using the physical dots per inch of the screen, divided by 25.4, so we copy that as well. You could use any other value there.
You will need to adapt the code should a second MouseArea ever be introduced, for example.
It's still largely dependent on private API, but it doesn't touch Qt code, at least.
Quick&Easy: enable/disable mouse and touch synthesizing
No need to patch things or doing any crazy tree lookups, just enable or disable mouse or touch synthesizing.
Qt::AA_SynthesizeTouchForUnhandledMouseEvents
Qt::AA_SynthesizeMouseForUnhandledTouchEvents
Just disable what you don't want, either mouse or touch to accept only authentic events.

Resources