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 a Rectangle 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 using Qt.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 a Rectangle, which has no text property ( I edited my previous message and replaced it by Text). 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 a Rectangle.

    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 a Component in that file. E.g. you would define Messages.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:

    1. Dynamically create a component, e.g. msgComponent from Messages.qml using Qt.CreateComponent()
    2. 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 like

    import "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!



  • @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 the bottom property of its parent works if the parent's clip property is false (which is the default). If clip is set to true 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 color transparent -> 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?

    0_1534337251947_85506d0d-8883-4dd3-a1c9-7ee44247eb11-image.png

    0_1534337524174_41b7e27d-ad9f-436c-bb26-0954207c934c-image.png

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

    0_1535294982329_b75c0c5d-2344-4af8-8085-9ee1ddc69c49-image.png

    where Messages.qml is

    import 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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.