i Am using Qt 5.12.8 , i have imported
import QtQml.Models 2.2
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
but i get this error :invalid property name minX (M16) . Can some one guide me what is my mistake!!
NewWindow {
id: newWindow
visible: !privateVars.isLoading && !privateVars.isEditing
x: (maxX-minX)/2
y: (maxY-minY)/2
minX: -parent.x //ERROR invalid property name minX (M16)
maxX: monitor.width - width - parent.x - additionalToolbarRightMargin -25 //ERROR invalid property name maxX (M16)
minY: -parent.y //ERROR invalid property name minY (M16)
maxY: monitor.height - height -parent.y //ERROR invalid property name maxY (M16)
onLoadClicked: privateVars.isLoading = true
//selectedMissionInstance: loadMissionWindow.selectedMissionInstance
onNewClicked:
{
//Create new mission in missionmodel and go to edit view
missionPlanningModel.newMissionClicked()
privateVars.isEditing = true
}
}
I guess you want to make a variables minX/minY/etc for NewWindow, not to set a value for existing ones.
If that's so you should declare it. Like that:
NewWindow {
id: newWindow
visible: !privateVars.isLoading && !privateVars.isEditing
x: (maxX-minX)/2
y: (maxY-minY)/2
property int minX: -parent.x //Now it's not firing an error
property int maxX: monitor.width - width - parent.x - additionalToolbarRightMargin -25
property int minY: -parent.y
property int maxY: monitor.height - height -parent.y maxY (M16)
onLoadClicked: privateVars.isLoading = true
//selectedMissionInstance: loadMissionWindow.selectedMissionInstance
onNewClicked:
{
//Create new mission in missionmodel and go to edit view
missionPlanningModel.newMissionClicked()
privateVars.isEditing = true
}
}
Related
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
I tried to make a function that will change button colors clockwise.
When I assign property var acolor: buttons.itemAt(0).color, the variable acolor changes value as buttons.itemAt(0).color changes. Why does this happen?
This is main.qml file:
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
Window {
id: root
visible: true
width: 600
height: 400
title: qsTr("My Window")
property int numberOfButtons: 9
GridLayout{
id: grid
columns: 3
anchors.fill: parent
Repeater {
id: buttons
model: root.numberOfButtons;
delegate: Mybutton {id: butt; color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1); number: index}
}
}
}
This is Mybutton.qml:
Rectangle {
id: rectangle
width: 50; height: 100
color: "red"
property int number: 0
MouseArea {
id: mouse
anchors.fill: parent
property var acolor: buttons.itemAt(0).color
onClicked: {
function rotate()
{
acolor = buttons.itemAt(0).color
console.log(acolor)//heare is #11754c
buttons.itemAt(0).color = buttons.itemAt(3).color
console.log(acolor)// but heare is #6c2c3d
buttons.itemAt(3).color = buttons.itemAt(6).color
buttons.itemAt(6).color = buttons.itemAt(7).color
buttons.itemAt(7).color = buttons.itemAt(8).color
buttons.itemAt(8).color = buttons.itemAt(5).color
buttons.itemAt(5).color = buttons.itemAt(2).color
buttons.itemAt(2).color = buttons.itemAt(1).color
buttons.itemAt(1).color = acolor
}
rotate()
}
}
}
First of all, your design is wrong. It is conceptually backwards to put the rotation functionality in the button when it acts on the grid layout. The rotate() function should be a member of the grid layout, and the you simply invoke it onClicked.
Second, according to typeof(buttons.itemAt(0).color) the type of color is object. Which means that acolor is a reference to that particular object, which explains why that reference points to another value once you change the color of the item at index 0.
One way to trick it to implicitly convert the color to a string is to use it like this:
var acolor = ""
acolor += buttons.itemAt(0).color
console.log(acolor)
buttons.itemAt(0).color = buttons.itemAt(3).color
console.log(acolor) // the same!!!
And now it will be preserved, because acolor is now a string rather than an object reference.
Also, you don't really need the property var acolor: buttons.itemAt(0).color part.
You can also explicitly convert the color to a string:
var acolor = buttons.itemAt(0).color.toString()
Also, by moving the rotate function to where it belongs you considerably simplify the mouse area in the button:
MouseArea {
anchors.fill: parent
onClicked: grid.rotate()
}
Update:
Note that if we do it like this:
property color acolor
function rotate() {
acolor = buttons.itemAt(0).color
console.log(acolor)
buttons.itemAt(0).color = buttons.itemAt(3).color
console.log(acolor) // still the same
}
it would work as logically expected. Now acolor is of type object, but you have an object to object assignment, which transfers the value to the other object, whereas with var it behaves like an object reference.
I am trying to load tabs dynamicly into a TabView from a different file. For this I am using Qt.createComponent and adds the component to the view. The tab is loaded but it's content does not show up and it is properly loaded. Like this:
TabView {
id:editor
Layout.minimumWidth: 50
Layout.fillWidth: true
}
Component.onCompleted: {
function newTab() {
var c = Qt.createComponent("tab.qml");
editor.addTab("tab", c);
var last = editor.count - 1;
editor.getTab(last).active = true;
}
newTab();
newTab();
}
And the "tab.qml" file:
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Tab {
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "lightgray"
TextArea {
anchors.fill: parent
}
}
}
What do I do wrong?
After reading #folibis clean-up suggestion I realized the way I got the Tab onCompleted handler wasn't working. Why I don't know. However replacing
var c = Qt.createComponent("tab.qml");
editor.addTab("tab", c);
var last = editor.count - 1;
editor.getTab(last).active = true;
with
var c = Qt.createComponent("tab.qml");
var tab = editor.addTab("tab", c);
tab.active = true
solved it.
I decided to rewrite this question. I tried to make it clear and short but it didn't work out.
What I am trying to achieve is an object I can put on anything (Rectangle, Image and so on) and make it respond to touch gestures. Unfortunately I ran into a problem I cannot solve. I couldn't find help so I try here.
Here is simple main.qml:
import QtQuick 2.5
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Touch surface test")
width: 640
height: 480
visible: true
Rectangle {
width: 200
height: 60
color: "blue"
MyTouchSurface {
id: myTouchSurface
anchors.fill: parent
}
}
}
and here is MyTouchSurface.qml
import QtQuick 2.5
MultiPointTouchArea {
id: myTouchSurface
// this is object I want to respond to touch gestures
property Item target: parent
// this is object I want to keep target in. I won't let target get out of it
property Item container: parent.parent
property double targetX: target.x
property double targetY: target.y
property double centerX: target.width / 2
property double centerY: target.height / 2
property double lastTouchX
property double lastTouchY
property double lastXDrag
property double lastYDrag
// here I calculate received touches and move target
onPressed: {
lastTouchX = touchPoints[0].sceneX
lastTouchY = touchPoints[0].sceneY
if (slidingAnimation.running)
slidingAnimation.stop()
}
onTouchUpdated: {
if (touchPoints.length) {
target.x += touchPoints[0].sceneX - lastTouchX
target.y += touchPoints[0].sceneY - lastTouchY
lastXDrag = touchPoints[0].sceneX - lastTouchX
lastYDrag = touchPoints[0].sceneY - lastTouchY
lastTouchX = touchPoints[0].sceneX
lastTouchY = touchPoints[0].sceneY
}
else
startSliding()
}
// when lifting fingers off screen I want to slide target across it's container
function startSliding() {
slidingAnimation.toX = target.x + lastXDrag * 10
slidingAnimation.toY = target.y + lastYDrag * 10
slidingAnimation.restart()
}
// This is animation responsible for sliding the target
ParallelAnimation {
id: slidingAnimation
property double toX
property double toY
property int animationDuration: 250
NumberAnimation {
target: myTouchSurface.target
property: "x"
to: slidingAnimation.toX
duration: slidingAnimation.animationDuration
easing.type: Easing.OutQuad
}
NumberAnimation {
target: myTouchSurface.target
property: "y"
to: slidingAnimation.toY
duration: slidingAnimation.animationDuration
easing.type: Easing.OutQuad
}
}
// this is how I keep target object within container
onTargetXChanged: {
if (container != null) {
if (target.x + centerX < 0)
target.x = -centerX
else if (target.x + centerX > container.width)
target.x = container.width - centerX
}
}
onTargetYChanged: {
if (container != null) {
if (target.y + centerY < 0)
target.y = -centerY
else if (target.y + centerY > container.height)
target.y = container.height - centerY
}
}
}
I want to have all calculating and functions within MyTouchSurface so it is easy to apply on other object and to use it in another project.
The problem I have is I don't know how to prevent target object from moving out of container. Well, the code here is working very nice but it also generates very ugly errors about binding loop.
What is going on is:
I check target's x and y when they changes
If the x or y is out of specified area I move them back
I receive signal "x changed" or "y changed" again
I receive error about loop because my function caused itself to execute again
So I am asking: Is there any other simple way to prevent object from flying off screen and not receive binding loop errors at the same time?
I know I can use Timer to check target's x and y from time to time, and bring them back.
I know I can change the easing and duration of the animation so it stops on the container bounds itself but looks like it was stopped.
Seriously. Is there no simple way?
Things that won't work:
stopping animation after object was detected outside container (if it would move really fast it will stop out of the screen )
stopping animation and then changing target's x or y
Thanks everyone helping me so far. It is nice to know I am not alone here :)
The solution is simply use Connections:
import QtQuick 2.5
MultiPointTouchArea {
id: myTouchSurface
// this is object I want to respond to touch gestures
property Item target: parent
// this is object I want to keep target in. I won't let target get out of it
property Item container: parent.parent
property double targetX: target.x
property double targetY: target.y
property double centerX: target.width / 2
property double centerY: target.height / 2
property double lastTouchX
property double lastTouchY
property double lastXDrag
property double lastYDrag
// here I calculate received touches and move target
onPressed: {
lastTouchX = touchPoints[0].sceneX
lastTouchY = touchPoints[0].sceneY
if (slidingAnimation.running)
slidingAnimation.stop()
}
onTouchUpdated: {
if (touchPoints.length) {
target.x += touchPoints[0].sceneX - lastTouchX
target.y += touchPoints[0].sceneY - lastTouchY
lastXDrag = touchPoints[0].sceneX - lastTouchX
lastYDrag = touchPoints[0].sceneY - lastTouchY
lastTouchX = touchPoints[0].sceneX
lastTouchY = touchPoints[0].sceneY
}
else
startSliding()
}
// when lifting fingers off screen I want to slide target across it's container
function startSliding() {
slidingAnimation.toX = target.x + lastXDrag * 10
slidingAnimation.toY = target.y + lastYDrag * 10
slidingAnimation.restart()
}
// This is animation responsible for sliding the target
ParallelAnimation {
id: slidingAnimation
property double toX
property double toY
property int animationDuration: 250
NumberAnimation {
target: myTouchSurface.target
property: "x"
to: slidingAnimation.toX
duration: slidingAnimation.animationDuration
easing.type: Easing.OutQuad
}
NumberAnimation {
target: myTouchSurface.target
property: "y"
to: slidingAnimation.toY
duration: slidingAnimation.animationDuration
easing.type: Easing.OutQuad
}
}
Connections{
target:myTouchSurface.target
onXChanged:{
if (container != null) {
if (target.x + centerX < 0)
target.x = -centerX
else if (target.x + centerX > container.width)
target.x = container.width - centerX
}
}
onYChanged:{
if (container != null) {
if (target.y + centerY < 0)
target.y = -centerY
else if (target.y + centerY > container.height)
target.y = container.height - centerY
}
}
}
// this is how I keep target object within container
// onTargetXChanged: {
// }
// onTargetYChanged: {
// }
}
I think your problem is that you update either targetX or target.x (resp. for y) inside of the property update handler (onTargetXChanged()).
This might be picked up as a biding loop by the QML engine as if you change target.x from onTargetXChanged() the signal onTargetXChanged() will trigger again as it's bound to it in property double targetX: target.x.
You can try something like this:
TouchArea {
property Item target // target is the Image object being moved
property double targetX: target.x
property double targetY: target.y
onTargetXChanged: {
/* if object is out of specified area move x respectively */
performPropertyUpdate(args)
}
onTargetYChanged: {
/* if object is out of specified area move y respectively */
performPropertyUpdate(args)
}
function performPropertyUpdate(args) {
/* actual setting of target.x or target.y */
}
}
To solve the issue myX should be an alias of x,
property alias myX: rectangle2.x
You're getting this problem cause myX is changing the value of x and x is changing the value of myX: a loop.
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.