I'm trying to load some QML form in QQuickWidget and keep getting: QML GroupBox: Binding loop detected for property "implicitWidth"
The simplified QML is:
import QtQuick 2.4
import QtQuick.Controls 1.2
GroupBox {
id: root
title: qsTr("1")
Column {
id: column1
width: parent.width
ComboBox {
id: cbComboBox
width: parent.width
currentIndex: 0
editable: false
}
GroupBox {
id: groupBox
title: "test"
width: parent.width //the problem
Label {
text:"1"
width: parent.width
}
}
}
}
It looks like for some reason I can't use parent.width or cbComboBox.width for groupBox. And root.width works but too wide. What I'm missing? I need nested GroupBox to have maximum width (with spacing).
According to the Qt GroupBox QML Type documentation
The implicit size of the GroupBox is calculated based on the size of its content.
It means the GroupBox will automatically use the size of its children to calculate its own size.
In your case, the only child is the Column whose width is equal to the GroupBox width. I think that is what's causing the binding loop.
If you set the width of the Column as said by #eyllanesc, the binding loop will disappear.
I would rather define the implicit width of the GroupBox (the width by default) in the QML part. In my example, the implicit width is 100px but it could be calculated from the widths of the children (ComboBox, other GroupBox,...).
// MyGroupBox.qml
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
GroupBox {
title: qsTr("1")
implicitWidth: 100
Column {
id: column1
width: parent.width
ComboBox {
id: cbComboBox
currentIndex: 0
editable: false
width: parent.width
}
GroupBox {
id: groupBox
title: "test"
width: parent.width
Label {
text: "1"
}
}
}
}
And it will possible to set a real width depending on your project directly from the C++ by changing the width of the root object.
// main.cpp
#include <QtQuickWidgets/QQuickWidget>
#include <QQuickItem>
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQuickWidget *view = new QQuickWidget;
view->setSource(QUrl::fromLocalFile("://MyGroupBox.qml"));
view->rootObject()->setWidth(800);
view->show();
return app.exec();
}
Related
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"
}
}
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
I'm using in my code KeyNavigation.tab property to make navigation workable in qml.
But the control SpinBoxis not working with it. for example if i have a control between it and the element i want it to navigate it wont respect the rule.
I'm going to illustrate with a real example.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
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;
return app.exec();
}
and
main.qml
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Controls 2.0
ApplicationWindow {
id: window
title: "Stack"
visible: true
height: 200
width: 400
Item {
id: page
anchors.fill: parent
width:parent.width
height: parent.height
ScrollView {
id:scrollView
anchors.fill:parent
Column{
width:parent.width
spacing:10
TextField {
id:textField
KeyNavigation.tab: spinBox1
implicitHeight: 30
font.bold: true
}
SpinBox {
id: spinBox1
KeyNavigation.tab: spinBox2
width: 100
height: 30
editable: true
}
ComboBox {
id:comboBox
//KeyNavigation.tab: spinBox2
anchors.topMargin: 10
textRole: "text"
}
SpinBox {
id: spinBox2
KeyNavigation.tab: textField
width: 100
height: 30
editable: true
}
}
}
}
}
Here spinBox1 wont jump to spinBox2 if we use tab.
This was tested on a windows 10 OS
The version of Qt used is 5.11.1
For some reason, the QQuickKeyNavigationAttached::keyPressed() is not called if the attached property is set on the SpinBox itself instead of its TextInput. So, using the attached property on the contentItem is a workaround:
SpinBox {
Component.onCompleted: contentItem.KeyNavigation.tab = spinBox
}
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")
}
My cpp application has a QMainWindow derived class, with QQuickView widget in the ui. Inside the view are a number of QML items which accept keyboard input. When an item is clicked, I call forceActiveFocus() on the clicked item. It all works from the time I launch the application, until the time I switch to another window.
If I switch to another application and back, or switch to another window within my application and back, calling forceActiveFocus() has no effect. The items are of a few different types, but here is a sample item:
TextInput {
id: textInput
anchors.fill: parent
inputMethodHints: Qt.ImhFormattedNumbersOnly
onActiveFocusChanged: console.log(activeFocus)
onEditingFinished:
{
}
MouseArea {
anchors.fill: textInput
onClicked: {
textInput.forceActiveFocus()
console.log("clicked")
}
}
}
When switching away I see activeFocus logged to the console as false. When I switch back again and click on the item, "clicked" is logged to the console, so the mouse event is being handled. However, onActiveFocusChanged is never called again.
I also tried an implementation with a FocusScope as the parent of the item, got the same behavior, with focus following my click until the point I switch away to some other window and back again.
UPDATE
After reading the comment from #user2436719, I've tried two minimal examples. It is only when using the QQuickView that this problem arises. Here is the QML app using a QML Window with the following main.qrc, which works just fine:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
color: "lightblue"
Rectangle {
id: textInputRect
color: "white"
height: 50
width: 150
anchors.centerIn: parent
TextInput {
id: textInput
anchors.fill: parent
inputMethodHints: Qt.ImhFormattedNumbersOnly
onActiveFocusChanged: console.log(activeFocus)
onEditingFinished:
{
}
}
}
}
The second is a CPP application with a QMainWindow derived class that has a QQuickView widget in the ui. This version exhibits the problem behavior. Here is the main.qrc:
import QtQuick 2.7
import QtQuick.Window 2.2
Rectangle {
anchors.fill: parent
color: "lightblue"
Rectangle {
id: textInputRect
color: "white"
height: 50
width: 150
anchors.centerIn: parent
TextInput {
id: textInput
anchors.fill: parent
inputMethodHints: Qt.ImhFormattedNumbersOnly
onActiveFocusChanged: console.log(activeFocus)
onEditingFinished:
{
}
}
}
}
From the QQuickView version, here is main:
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
MainWindow window;
QQuickView* view = new QQuickView;
window.setView(view);
window.show();
return app.exec();
}
And here is how I set the QQuickView in the MainWindow:
void MainWindow::setView(QQuickView *value)
{
view = value;
QWidget *container = QWidget::createWindowContainer(view, this);
view->setSource(QUrl("qrc:/main.qml"));
ui->verticalLayout->addWidget(container);
}
Okay, this is QTBUG-34414. At the bottom of the comments for that bug a workaround is posted. The posted workaround fixed the problem for me, in the case of switching to other windows of my application, or to other applications. There was still no focus after closing dialogs. Putting this override in my window class fixed the problem for both cases:
bool MyWindow::event(QEvent *event)
{
if (event->type() == QEvent::ActivationChange ||
event->type() == QEvent::WindowUnblocked) {
if(view->isActive()) { //view is pointer to my QQuickView
window()->activateWindow();
return true;
}
}
// handle events that don't match
return QWidget::event(event);
}
This override worked for me with Qt 5.7 on OSX Sierra.