I have a QML singleton file which I use it for saving user variables to be used in the application.
I use the same file for storing variables like #define in C++.
The issue is if I add new parameters and compile and run the app, the values that I read from the old variables from the singleton file reads junk values until I add a console.log().
This happens every single time I add new variables to the file.
Is this a known bug? I am using Qt 5.8 on a Yocto build.
Edit: Added a minimal project files to reproduce the error. I tried this in Ubuntu 16 as well.
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Test")
Scene
{
width: parent.width
height: parent.height
anchors.centerIn: parent
}
}
Style.qml
pragma Singleton
import QtQuick 2.0
QtObject
{
property color green: "#558B2F"
property color red: "#DD2C00"
property color black: "black"
property int dialogPopupDuaration: 100
property int dialogTimeoutValue : 1500
property int splashTimeout: 5000
property int rotation: 180
//Dialog Types
property int dialogInfo: 0
property int dialogProcessing: 1
property int dialogSuccess: 2
property int dialogFailure: 3
//Settings
property int manualOffset: 0
property int calibrationTimeout: 1
property bool isUnitMM: true
property bool isBrightnessHigh: false
property bool isDMPInit: false
property int batteryThreshold: 33
property int batterWarningOffset: 3
//Uncomment the below lines and run
//the app will no longer print the qW
//until i console.log() in main.qml
// readonly property int boneS: 1
// readonly property int boneN: 0
// property int boneType: boneS
// property int boneTN: boneN
// property int boneTP: boneN
//Default quaternion values for the 3D obj
//to face towards the screen
property real qX: 0.0
property real qY: -1.0
property real qZ: 0.0
property real qW: -0.5
property real tolerance: 0.02
//IMU requires 30s from boot to settle down
//so if user tries to calibrate it before that
//use this bool to show warning
property bool isThirtySecElapsed: false
readonly property string appVersion: "v1.0.2"
}
Scene.qml
import QtQuick 2.0
import "."
Rectangle
{
id: scene
anchors.fill: parent
width: parent.width * 0.5
height: width
color: "grey"
Text
{
text: Style.qW
anchors.centerIn: parent
font.bold: true
font.pointSize: 20
fontSizeMode: Text.Fit
color: "white"
}
Component.onCompleted:
{
//console.log(Style.qW)
}
}
qmldir
singleton Style 1.0 Style.qml
Related
I am trying to add set of custom properties to be included by several labels on my QML. The idea is to make a style, but I keep getting these errors:
qrc:/TestPage.qml:18:9: Unable to assign [undefined] to QColor
qrc:/TestPage.qml:17:9: Unable to assign [undefined] to double
qrc:/TestPage.qml:16:9: Unable to assign [undefined] to QString
I was following the thread below but did not work for me.
Unable to assign [undefined] to QColor
Here is my label:
import "Theme"
Label
{
font.family: Theme.tfont
font.pointSize: Theme.tpointSize
color: Theme.tcolor
text: "text"
}
and here is my Theme.qml file:
pragma Singleton
import QtQuick
QtObject
{
readonly property string tfont: {return "Calibri"}
readonly property real tpointSize: {return 28}
readonly property string tcolor: {return "black"}
}
any ideas why it won't resolve the property?
Check that example it uses a Style.qml to define a global theme. As Stephen Quan already said you should create a qmldir to define the singleton.
The important part here is to also include the qmldir and the Theme.qml in your CMakeLists.txt or pro.
CMakeLists.txt
...
qt_add_qml_module(appuntitled
URI untitled
VERSION 1.0
QML_FILES
main.qml
qmldir
Theme.qml
)
...
qmldir
singleton Theme 1.0 Theme.qml
Theme.qml
pragma Singleton
import QtQuick
QtObject {
readonly property string tfont: "Calibri"
readonly property real tpointSize: 28
readonly property string tcolor: "black"
}
main.qml
import QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Label {
font.family: Theme.tfont
font.pointSize: Theme.tpointSize
color: Theme.tcolor
text: "text"
}
}
I made the following changes to your app:
Declare qmldir
Don't need import "Theme"
Refactor AppLabel
Don't use return when declaring properties declaratively
import QtQuick
import QtQuick.Controls
Page {
AppLabel { text: "text" }
}
//AppLabel.qml
import QtQuick
import QtQuick.Controls
Label {
font.family: Theme.tfont
font.pointSize: Theme.tpointSize
color: Theme.tcolor
}
//qmldir
singleton Theme 1.0 Theme.qml
//Theme.qml
pragma Singleton
import QtQuick
QtObject
{
readonly property string tfont: "Calibri"
readonly property real tpointSize: 28
readonly property string tcolor: "black"
}
You can Try it Online!
how can i get gridView.itemAtIndex(index).color?
what is i have tried:
contentrepeater.itemAt(5).gridView.model.color;
contentrepeater.itemAt(5).gridView.itemAtIndex(5).color;
But it doesn't work
Rectangle {
anchors.top: bar.bottom
Layout.fillHeight: true
Layout.fillWidth: true
Repeater {
id: contentrepeater
model: 11
Rectangle {
anchors.fill: parent
color: 'red'
visible: false
GridView {
id: gridView
anchors.fill: parent
anchors.topMargin: 10
anchors.leftMargin: 10
cellWidth: 150
cellHeight: 170
clip: true
model: 11
delegate: Rectangle{
height: 160
width: 140
color: '#333333'
}
}
}
}
}
Ultimately you probably don't want to do it that way. It will be hackish and error-prone. For example GridView only provides item access based on position coordinates, not indexes. So you'd need to dive into its children which are going to be created dynamically... it's possible but very messy and not really supported API.
You are better off defining your item models first, then using the GridView (or whatever) to display them. That way you can manipulate objects in the models and changes will be reflected in the view (instead of the other way around like you're trying now).
This example (based on your posted code) creates 4 layouts with 11 squares each and animates the color in each square using a timed script. Note that we need separate instances of the models for each of the GridViews within contentrepeater (otherwise it is only shown in the last view). So the example is a bit more convoluted since the item models are being created dynamically.
I should add that in a "real" application I'd use a different method of tracking the created item models instead of looking them up in the display hierarchy like I have it here. The main point this is trying to demonstrate is to manipulate the displayed items (delegates) via changes to the model data.
import QtQuick 2.9
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import QtQml.Models 2.3
Pane {
id: root
width: 400
height: 650
padding: 9
// rectangle items to create per model
property int itemsPerModel: 11
// prototype object model
property Component itemModel: ObjectModel {}
// prototype model item
property Component delegate: Rectangle {
height: 30
width: 30
color: '#333333'
}
// Creates a new ObjectModel with some Rectangle items as children
function newItemModel() {
var model = itemModel.createObject(root);
for (var i=0; i < itemsPerModel; ++i)
model.append(delegate.createObject(root));
return model;
}
SequentialAnimation {
id: animate
running: true
loops: Animation.Infinite
ScriptAction {
property string nextColor: "blue"
property int nextSet: 0
property int nextItem: 0
script: {
contentrepeater.itemAt(nextSet) // the Rectangle within the GridLayout
.children[0] // the gridView within the Rectangle
.model.get(nextItem) // the model's delegate item (a Rectangle)
.color = nextColor; // set the new color on it.
// advance to next item or set of items.
nextItem = (nextItem+1) % root.itemsPerModel;
if (!nextItem)
nextSet = (nextSet+1) % contentrepeater.count;
nextColor = (nextColor === "blue" ? "orange" : nextColor === "orange" ? "white" : "blue");
}
}
PauseAnimation { duration: 100 }
}
GridLayout {
columns: 2
anchors.fill: parent
Repeater {
id: contentrepeater
model: 4
Rectangle {
color: 'red'
width: 150
height: 170
GridView {
id: gridView
anchors.fill: parent
anchors.topMargin: 10
anchors.leftMargin: 10
cellWidth: 40
cellHeight: 40
clip: true
// here we need a unique instance of the ObjectModel
model: root.newItemModel()
}
}
}
}
}
I want to programmatically read a string generated in runtime by a basic Qt GUI application.
The string appears on the screen but I don't have the source and I want to pass this string to another script.
Here's the relevant .qml file:
import QtQuick 1.0
Rectangle {
id: tagCloud
SystemPalette { id: palette } //we get the system default colors from this
//public API
property variant model
property color baseColor: palette.base
property color textColor: palette.text
property int textFontSize: 16
color: baseColor
Flow {
id: flow
width: parent.width
spacing: 15
anchors.margins: 4
anchors.verticalCenter: parent.verticalCenter
//property int maxHeight:0
Repeater {
id: repeater
model: tagCloud.model
Text {
id: textBlock
text: category
font.pointSize: tagCloud.textFontSize;
}
}
}
}
Is there an easy way to get the "category" string as it's being generated?
Edit: This is the link to the application,
http://cybertron.cg.tu-berlin.de/eitz/projects/classifysketch/sketchpad_win.zip
Element.qml
Item{
property int step
property int minValue
property int maxValue
property int value //should accept values of form i*step+minValue
}
main.qml
Element{
step:2
minValue:-7
maxValue:7
value:0 //not an acceptable value(2*i-7), should convert to 1 or -1
}
If I set the value, it should convert the value to nearest step*i+minValue,
i.e. 0 to 1 and then emit valueChanged().
I want the valueChanged() signal to be emitted only when its value is step*i+minValue.
You cant do a pre test and on it the valueChanged signal will be sent.
the only solution is to do the test in the onValueChanged slot and send a custom signal, you most not send valueChanged() sigal cause it's connected to the onValueChanged Slot.
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.2
Item{
property int step :2
property int minValue :-7
property int maxValue: 7
property int value: 0 //should accept values of form i*step+minValue
signal sgnValueChanged(int value)
Column{
TextInput{
id:input
width: 100
height: 20
}
Rectangle{
id:button
width: 100
height: 20
color:"#f0ffff"
MouseArea{
anchors.fill:parent
onClicked:
{
value = parseInt(input.text)
}
}
}
}
onValueChanged:
{
if(value >= minValue && value <= maxValue)
{
sgnValueChanged(step * value + minValue)
}
else
{
console.log("not acceptable value")
}
}
}
As far as I know there is no way to set a property validator. A possible workaround is shown below. Consider for instance a property that accepts only positive numbers. Such a property can be coded as follows:
Item {
property int value: 0
property int _value: 0
on_ValueChanged: {
if(_value > 0)
value = _value;
}
}
The same approach can be used in C++, if Item is your custom class.
I have rather strange scenario whereby if I launch a subwindow that contains a ListView with a moderately complex delegate and enough items to comfortably exceed the visible area, the entire subwindow will immediately close on launch.
Reducing the complexity of the delegate will allow the window to open, but then rapidly scrolling the ListView will forcibly close it.
This SSCCE triggers the effect on my laptop, but on a more powerful machine it may only do it whilst scrolling (or perhaps the delegate may need to be more complex):
import QtQuick 2.3
import QtQuick.Window 2.0
Window {
width: 300
height: 200
Component.onCompleted: {
win.createObject( null );
}
Component {
id: win
Window {
width: 600
height: 400
visible: true
ListView {
id: view
anchors.fill: parent
model: 100
boundsBehavior: Flickable.StopAtBounds
clip: true
delegate: Rectangle {
width: view.width
height: 24
property int debugLevel: index % 3
property int timestamp: index * 1000
property int message: index
color: "darkgray"
Row {
anchors.fill: parent
Repeater {
id: delegateRepeater
property list< QtObject > roleModel: [
QtObject {
property string label: timestamp
property int itemWidth: 100
},
QtObject {
property string label: debugLevel
property int itemWidth: 100
},
QtObject {
property string label: message
property int itemWidth: view.width - 100 - 100
}
]
model: roleModel
Item {
width: itemWidth
anchors {
top: parent.top
bottom: parent.bottom
}
Text {
anchors {
fill: parent
leftMargin: 4
}
verticalAlignment: Text.AlignVCenter
text: label
elide: Text.ElideRight
}
Rectangle {
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
}
width: 1
visible: index != ( delegateRepeater.count - 1 )
color: "white";
}
}
}
}
}
}
}
}
}
There doesn't seem to be any particular part of the code that is causing the problem, removing any of the objects in the delegate reduces the probability of the subwindow closing.
I've added the debugging tag because my main problem is that this effect produces no debug output. If I add a breakpoint into the subwindow's destruction handler (Component.onDestruction) then there is a single stack entry pointing at the model: roleModel statement - but removing the entire Repeater and replacing with a copy-and-pasted equivalent yields the same results minus the stack entry.
So I would be grateful is anyone knows of a way of getting more information from this pure QML example.
As noted by #BaCaRoZzo the changing of behaviour by modifying the delegate code seems to be an unrelated side-issue.
The real cause is because it turns out you cannot create new root contexts (i.e. top-level windows) from QML. This was hinted at being resolved when Qt Quick Components were released, but the blog post boasting of Window doesn't explicitly state this. Creating a new Window and passing null for the parent technically works but the result seems to be very unstable.
Thankfully in my circumstance I'm creating a QML/C++ application so I've solved the issue by creating new root contexts from Q_INVOKABLE methods on the C++ side. But if you're developing a pure QML application, it seems that you are out of luck.