Rectangle with onEditingFinished
-
Hi,
I have the following code:import VPlayApps 1.0 import QtQuick 2.0 import QtQuick 2.7 Page { title: qsTr("Add a Friend") Rectangle { id: root color: "lightblue" anchors.fill: parent AppTextField { id: addName x: dp(30) y: dp(30) anchors.margins: 15 borderWidth: 3 borderColor: "blue" backgroundColor: "lightgreen" clearsOnBeginEditing: true radius: 25 cursorPosition: 0 maximumLength: 85 placeholderText: "Name:" placeholderColor: "darkblue" validator: RegExpValidator { regExp: /[A-z]/ } onEditingFinished: { if (addName.text == "") { Rectangle { text: "Enter the name." } } } } }
Eventually the idea would be checking the name entry and if it is incorrect display a rectangle in which a text would instruct the user to correct the errors. My problem is that I keep getting the following error message: Expected token {,}. The location is between Rectangle and {.If I put a "," there I get a message that an } is missing from the end of the code and Qt deletes the "," .
Am I missing something from somewhere?
Thank you. -
@gabor53
You cannot use declarative-style QML definitions inside JavaScript code directly. If you want to create aRectangle
inside your JS, then you must do it dynamically.For example, declare a component somewhere
Component { id: notificationMessage Text { //set positioning + size properties here or at object creation time } }
Then:
onEditingFinished: { if (addName.text === "") { //Set a relevant visual item as parent, e.g. yourPageId var popup = notificationMessage.createObject(yourPageId, {text: "Enter the name."}) } }
Notes:
You may also create the component dynamically first usingQt.createComponent()
, if you don't want to declare it inline in your QML code. -
Hi @Diracsbracket ,
I changed the code like this:import VPlayApps 1.0 import QtQuick 2.0 import QtQuick 2.7 Page { title: qsTr("Add a Friend") Rectangle { id: root color: "lightblue" anchors.fill: parent Component { id: notificationMessage Rectangle { height: dp(20) color: "#be1717" width: dp(200) border.color: "darkred" border.width: 5 } } Text { id: id text: "ID:" x: dp(30) y: dp(30) font.pixelSize: 45 } AppTextField { id: addName anchors.top: id.bottom x: dp(30) anchors.margins: 30 borderWidth: 3 borderColor: "blue" backgroundColor: "lightgreen" clearsOnBeginEditing: true radius: 25 cursorPosition: 0 maximumLength: 85 placeholderText: "Name:" placeholderColor: "darkblue" validator: RegExpValidator { regExp: /[A-z]/ } onEditingFinished: { if (addName.text == "") { var popup = notificationMessage.createObject(root, { text: "Enter the Friend's name." }) } } } } }
There is no error message and nothing happens when there is no character in the name field. What is still wrong with it?
Thank you. -
Hi @gabor53
The component you created is aRectangle
, which has notext
property ( I edited my previous message and replaced it byText
). Unfortunately, no error is generated when using a non-existing property in the argument list of a dynamically generated object.If you want to avoid this, you could assign the property after the creation, like so:
var popup = notificationMessage.createObject(root) popup.text = "Enter the Friend's name."
This would have generated an error, if
popup
were aRectangle
.So in your case, you could use the following:
Component { id: notificationMessage Rectangle { height: 20 width: 200 property alias text: msg.text Text { id: msg anchors.fill: parent } } }
-
@Diracsbracket
Thank you very much. This works great.
Just one more question:
I can use the notificationMessage component into a new file named Messages.qml. Is it possible to access in addaFriendP1.qml the notificationMessage component from Messages.qml? I tried whatever I found on the internet, but none of them worked. (I still want to use NotificationMessage in the if statement.
Thank you. -
@gabor53
If you define your notification message in a separate QML file, then you shouldn't define it as aComponent
in that file. E.g. you would defineMessages.qml
as:Rectangle { height: 20 width: 200 property alias text: msg.text Text { id: msg anchors.fill: parent } }
Then, the dynamic object instantiation consists of two step:
- Dynamically create a component, e.g.
msgComponent
fromMessages.qml
usingQt.CreateComponent()
- Dynamically create the object from that component using
msgComponent.createObject()
http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html
I guess this rather tedious approach is due to the declarative nature of QML?
To save you the trouble, you could put this dynamic creation code inside a JS source file e.g. "code.js" which you would then import first likeimport "code.js" as Js
The JS code could look as follows:
function createMsg(parent, args) { var msgComp = Qt.CreateComponent("Message.qml") var msg = msgComp.createObject(parent, args); return msg }
If you rather not recreate the component all over again, you could also do something like:
var msgComp //global JS variable <-- usually not recommended though function createMsg(parent, args) { if (msgComp!==undefined) msgComp = Qt.CreateComponent("Message.qml") var msg = msgComp.createObject(parent, args); return msg }
Then in your QML code, simply call this function whenever you need as follows:
onEditingFinished: { if (addName.text === "") { var popup = Js.createMsg(yourPageId, {text: "Enter the name."}) } }
The possibilities are plenty!
- Dynamically create a component, e.g.
-
@Diracsbracket
Thank you for the detailed explanation. I chose to create the Js file (code.js) and it looks like this:function createMsg(parent, args) { var msgComp = Qt.createComponent("Messages.qml") var msg = msg.Comp.createObject(parent, args) return msg }
I changed the Messages.qml:
import QtQuick 2.0 import QtQuick 2.2 import VPlayApps 1.0 Rectangle { id: notificationSquare height: dp(30) anchors.top: addName.bottom anchors.left: addName.left anchors.topMargin: 20 color: transparent width: dp(250) border.color: "#ff0000" border.width: 2 property alias text: msg.text Text { id: msg font.bold: true horizontalAlignment: Text.AlignHCenter color: "red" font.pointSize: 20 anchors.fill: notificationSquare anchors.horizontalCenter: notificationSquare.horizontalCenter anchors.verticalCenter: notificationSquare.verticalCenter } }
AddaFriendP1.qml has id: add1 and the relevant code:
onEditingFinished: { if (addName.text == "") { var popup = Js.createMsg(add1, { text: "Enter the Friend's name." }) } }
I have no error message, but the warning message doesn't pop up either. Did I miss something?
Thank you for your help. -
@gabor53 said in Rectangle with onEditingFinished:
var msg = msg.Comp.createObject(parent, args)
Must be
var msg = msgComp.createObject(parent, args)
Also, if a component is to be reusable, it is usually better to use
parent
properties to determine its size/anchoring rather than to hard-code some element's id.Rectangle { id: notificationSquare ... anchors.top: parent.bottom //<- should work if parent does not have clip: true? //addName.bottom anchors.left: parent.left //addName.left }
As mentioned in the comments above, anchoring the
top
of a child to thebottom
property of itsparent
works if the parent'sclip
property isfalse
(which is the default). Ifclip
is set totrue
the child will not be visible with the above anchoring.color: transparent
Did that not generate an error in your
Application Output
window?
There is no colortransparent
-> should be"transparent"
between quotes. -
@Diracsbracket
There was no error message at all. -
@gabor53 said in Rectangle with onEditingFinished:
There was no error message at all.
There was no error message at all in the
Application output
view when you tried to run it?If those errors really are not reported, then you really should solve that problem first and find out why, but I suspect you may only have been looking at the
Compile Output
view or so. -
Hi @Diracsbracket ,
I fixed everything you highlighted and you are right, I focused on the compile output. In spite of the corrections it still doesn't display the rectangle and the text. Here are my changes:var msgComp = Qt.createComponent("Messages.qml") var msg = msgComp.createObject(parent, args) onEditingFinished: { if (addName.text === "") { var popup = Js.createMsg(add1, { text: "Enter the Friend's name." }) Rectangle { id: notificationSquare height: dp(30) anchors.top: parent.bottom anchors.left: parent.left anchors.topMargin: 20 color: "transparent"
It seems correct but it is not working. Thank you for your help.
-
@gabor53
I think it's best if you try the following minimal test program, run it and compare it with what you have:main.qml
:import QtQuick 2.11 import QtQuick.Window 2.11 import QtQuick.Controls 2.4 import "code.js" as Js ApplicationWindow { id: window visible: true width: 640 height: 480 title: qsTr("Hello World") Rectangle { id: root color: "lightblue" anchors.fill: parent focus: false Text { id: id text: "ID:" x: 30 y: 30 font.pointSize: 16 focus: false } TextField { id: addName anchors.top: id.bottom x: 30 anchors.margins: 30 maximumLength: 85 placeholderText: "Add Name" focus: true property Message msg onLengthChanged: { if (msg && length>0) msg.destroy() } onEditingFinished: { if (length === 0) msg = Js.createMsg(addName, {"text": "Enter the Friend's name."}) else { focus = false console.debug("OK") } } } }
code.js
function createMsg(parent, args) { var msgComp = Qt.createComponent("Message.qml") var msg = msgComp.createObject(parent, args) return msg }
-
@Diracsbracket
Sorry for the late response. I needed to buy a new computer and I am still setting it up. -
@gabor53 said in Rectangle with onEditingFinished:
I needed to buy a new computer and I am still setting it up.
I went through the same routine not so very long ago. Good luck!
-
@Diracsbracket
Thank you. Now it seems to be working (both the new computer and the program).
I ended up with another issue:
To make Messages reusable I changed the anchoring from addName to parent. But addName is a child of addFriend1 so it is not aligned with addName. How can I tell the Rectangle from Messages in addFriend1 that the parent now is addName?
Thank you. -
@gabor53
Don't you pass the desired parent object at object creation time? Like this:function createMsg(parent, args) { var msgComp = Qt.createComponent("Message.qml") var msg = msgComp.createObject(parent, args) return msg }
-
@Diracsbracket
I do. And the rectangle and the text is in the the top left corner. -
@gabor53
Show your result and your anchoring. They must be wrong.Using the test code as above (with a slight modification to destroy the message) I get this:
Rectangle { id: root color: "lightblue" anchors.fill: parent focus: false Text { id: id text: "ID:" x: 30 y: 30 font.pointSize: 16 focus: false } TextField { id: addName anchors.top: id.bottom x: 30 anchors.margins: 30 maximumLength: 85 placeholderText: "Add Name" focus: true //validator: RegExpValidator {regExp: /^[a-zA-Z ]{2,30}$/} property Message msg onLengthChanged: { if (msg && length>0) msg.destroy() } onEditingFinished: { if (length === 0) msg = Js.createMsg(addName, {"text": "Enter the Friend's name."}) else { focus = false console.debug("OK") } } } }
where
Messages.qml
isimport QtQuick 2.11 Rectangle { id: notificationSquare height: 30 anchors.top: parent.bottom anchors.left: parent.left anchors.topMargin: 20 color: "transparent" width: 250 border.color: "#ff0000" border.width: 2 property alias text: msg.text function destroy() { this.destroy() } Text { id: msg font.bold: true horizontalAlignment: Text.AlignHCenter color: "red" font.pointSize: 12 anchors.fill: parent anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter } }
-
@Diracsbracket
I figured out what I did incorrectly. Somehow I deleted the root rectangle.
Thank you for your detailed explanations. I learnt a lot.