Results 1 to 16 of 16

Thread: Changing background of every instance of a QML component (button)

  1. #1
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Changing background of every instance of a QML component (button)

    Hi,

    I'm developing a little app where the user can change the design (background and button image).

    My QML component 'Button' looks like that:
    Qt Code:
    1. // Button.qml
    2.  
    3. import QtQuick 2.4
    4.  
    5. Rectangle
    6. {
    7. id: button
    8. property alias image: image
    9. property alias mousearea: mousearea
    10. property alias text: text.text
    11.  
    12. width: 90
    13. height: 30
    14. color: "transparent"
    15.  
    16. BorderImage
    17. {
    18. id: image
    19. source: mousearea.pressed ? "qrc:/img/buttons/cyan_hover.png" : "qrc:/img/buttons/cyan.png"
    20. width: parent.width
    21. height: parent.height
    22. border { left: 25; top: 25; right: 25; bottom: 25 }
    23. horizontalTileMode: BorderImage.Stretch
    24. verticalTileMode: BorderImage.Round
    25. }
    26.  
    27. MouseArea
    28. {
    29. id: mousearea
    30. anchors.fill: parent
    31. acceptedButtons: Qt.LeftButton
    32. cursorShape: "PointingHandCursor"
    33. }
    34.  
    35. Text
    36. {
    37. id: text
    38. anchors.centerIn: parent
    39. text: "Button"
    40. color: "white"
    41. font.bold: true
    42. }
    43. }
    To copy to clipboard, switch view to plain text mode 
    It has a pre-defined background image (color: cyan) and a pressed-effect (background changes to cyan_hover).

    In my main QML file, I create about 15 instances of those buttons ("Button black", "Button gray", "Button brown", "Button blue", "Button cyan" and so on...).
    When the user clicks on one of those buttons, every button image should change to the image that was selected, example:
    User clicks button "Button black" --> background image of every button should change to "qrc:/img/buttons/black.png".

    This is how I create those instances:
    Qt Code:
    1. //main.qml
    2. import QtQuick 2.4
    3. import QtQuick.Window 2.2
    4.  
    5. Window
    6. {
    7. id: window
    8. visible: true
    9. width: 350
    10. height: 500
    11.  
    12. Rectangle
    13. {
    14. id: rectangleLayout
    15. anchors.fill: parent
    16.  
    17. Image
    18. {
    19. id: imageBackground
    20. source: "qrc:/img/backgrounds/cyan.jpg"
    21. width: parent.width
    22. height: parent.height
    23. fillMode: Image.Stretch
    24. }
    25.  
    26. Button
    27. {
    28. id: buttonDesignBlack
    29. anchors.top: rectangleHeader.bottom
    30. anchors.left: rectangleLayout.left
    31. anchors.topMargin: 30
    32. anchors.leftMargin: 10
    33. anchors.horizontalCenter: rectangleLayout.horizontalCenter
    34. height: 50
    35. mousearea.onClicked:
    36. {
    37. // there I have to put the code to change design
    38. }
    39. text: "Button black"
    40. }
    41. // another 14 instances of 'Button'
    42. }
    To copy to clipboard, switch view to plain text mode 

    I have two questions about that now:
    1. Is there a way to change the background image of all 15 instances with one line of code or do I have to change the source property of each instance by hand, like this:
    Qt Code:
    1. mousearea.onClicked:
    2. {
    3. buttonDesignBlack.image.source = buttonDesignBlack.mousearea.pressed ? "qrc:/img/buttons/black_hover.png" : "qrc:/img/buttons/black.png"
    4. buttonDesignXX.image.source = buttonDesignXX.mousearea.pressed ? "qrc:/img/buttons/black_hover.png" : "qrc:/img/buttons/black.png"
    5. // ...
    6. }
    To copy to clipboard, switch view to plain text mode 

    2. The way I try it above does apply the changes, hence the new background is set correctly, but the pressed event does not change the background anymore. It works without doing anything in the onClicked scope, so I know the error has to be there.
    Maybe the problem is, that the pressed event & changing background image is overwritten immediately by the onClicked signal?? But I also tried to press and hold the mouse button down on the button, so the onClicked signal is not yet emitted, but the background doesn't change anyway!
    When running the app, the pressed event + background image change works exactly ONE TIME, after that it doesn't work anymore. So I think the problem is that I overwrite something when executing the code in onClicked scope... Does anyone know where my error is??

    Thank you in anticipation!

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Changing background of every instance of a QML component (button)

    What you need are two properties (one for each state image) that is accessible from "everywhere".

    One way to do that is a singleton type.

    Qt Code:
    1. // Theme.qml
    2. pragma Singleton
    3.  
    4. import QtQuick 2.0
    5.  
    6. Item {
    7. property url buttonDownSource
    8. property url biuttonUpSource
    9. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. // qmldir
    2. singleton Theme 1.0 Theme.qml
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // Button.qml
    2. Item {
    3. //...
    4.  
    5. Image {
    6. source: mouseare.pressed ? Theme.buttonDownSource : Theme.buttonUpSource
    7. }
    8. }
    To copy to clipboard, switch view to plain text mode 

    And then you assign whatever image URLs to those two properties.

    As for (2), you are assigning a value to a property. This overwrites any binding on that property.

    Cheers,
    _

  3. #3
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Re: Changing background of every instance of a QML component (button)

    Hi and thank you for your reply!

    Well, singleton sounds interesting, I will take a look at it immediatelly :-)

    As for (2), you are assigning a value to a property. This overwrites any binding on that property.
    Can you explain that, I don't understand it exactly.
    When I define the source in Button.qml like this:
    Qt Code:
    1. source: mousearea.pressed ? "img_pressed.png" : "img.png"
    To copy to clipboard, switch view to plain text mode 
    Then it works great everytime i press and hold the button. After releasing, the normal "img.png" is displayed.

    But as soon as I try to change the image using the same mechanism as above in onClicked event, then it doesn't work correctly anymore:
    Qt Code:
    1. mouseare.onClicked:
    2. {
    3. buttonXX.image.source = buttonXX.mousearea.pressed ? "img_pressed.png" : "img.png"
    4. }
    To copy to clipboard, switch view to plain text mode 
    You mean, I am overwriting something, but where is the problem with it? Why isn't the img_pressed.png displayed anymore when pressing + holding the mouse button on buttonXX after the onClicked has changed its background image?

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Changing background of every instance of a QML component (button)

    Quote Originally Posted by Binary91 View Post
    Qt Code:
    1. source: mousearea.pressed ? "img_pressed.png" : "img.png"
    To copy to clipboard, switch view to plain text mode 
    Then it works great everytime i press and hold the button. After releasing, the normal "img.png" is displayed.
    This is called a property binding. The value of the property is bound to an expression.
    Any change of a property inside that expression leads to a reevaluation of the expression, potentially leading to a different value.

    Quote Originally Posted by Binary91 View Post
    But as soon as I try to change the image using the same mechanism as above in onClicked event, then it doesn't work correctly anymore:
    Qt Code:
    1. mouseare.onClicked:
    2. {
    3. buttonXX.image.source = buttonXX.mousearea.pressed ? "img_pressed.png" : "img.png"
    4. }
    To copy to clipboard, switch view to plain text mode 
    This is an assignment of a value to the property.
    The imperative JavaScript code gets evaluated and the result is assigned to the property.
    After that line the value of "source" is either "img_pressed.png" or "img.png".

    Quote Originally Posted by Binary91 View Post
    Why isn't the img_pressed.png displayed anymore when pressing + holding the mouse button on buttonXX after the onClicked has changed its background image?
    Lets say that the mouse was not pressed when that code gets executed.
    The result of the conditional assignment is "img.png".

    So buttonXX.image.source is "img.png", equivalen to writing
    Qt Code:
    1. source: "img.png"
    To copy to clipboard, switch view to plain text mode 
    The property is bound to a fixed value.

    Cheers,
    _

  5. #5
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Re: Changing background of every instance of a QML component (button)

    Ahh now I got it! Yes, that sounds logically...

    So I think I could fix that when changing the assignment to a property binding, right?

    Is that possible from outside of the object?

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Changing background of every instance of a QML component (button)

    Yes, using Qt.binding http://doc.qt.io/qt-5/qml-qtqml-qt.html#binding-method

    But you don't need that once you have globally accessible "theme" properties since the binding never changes, only its values.

    Cheers,
    _

  7. #7
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Re: Changing background of every instance of a QML component (button)

    Hi,

    ok, you're right. The most logical way is to use a global Item with the two image sources and then binding its properties to the Button component, so I only have to change the Items properties and the changes are immediatelly applied in my Buttons...

    So the singleton way is exactly for these purposes? You said "one way", are there any other ways to create global objects in QML? (Sorry for all those beginner questions, but I'm trying to get an overview of all this stuff :-P )

  8. #8
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Changing background of every instance of a QML component (button)

    There is another option: an appropriately id'ed object in the main QML file.

    The id lookup rules will find id values defined in the main QML from any piece of QML that runs in the same engine.

    More like QML equivalent of a global variable rather than a singleton.

    The disadvantage is that any file-local id with the same value will "hide" that "global" object, the IDE has no way of identifying the object (no completion support), etc.
    The advantage is that you don't need a separate QML file and no qmldir file like for singletons.

    Given the choice I would go for the singleton.

    Cheers,
    _

  9. #9
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Re: Changing background of every instance of a QML component (button)

    The id lookup rules will find id values defined in the main QML from any piece of QML that runs in the same engine.
    Ah, that sounds interesting! How does it look the other way round? How "big" is the id scope of a *.qml file other than the main.qml? I mean, when I'm right, all objects in a specific *.qml file can access each other by its id, but a "inter-qml-file-access" via id isn't possible? (except the "global" ones defined in main.qml)? So the id scope is limited to the qml file, right?

    There is another option: an appropriately id'ed object in the main QML file.
    I also found a third way for my purpose, I just placed the url properties to the button's parent object and bound the image source not directly in the specific component file but after creating the instances in main.qml, like that:
    Qt Code:
    1. Rectangle
    2. {
    3. property string buttonStd = "qrc:/img/XX.png"
    4. property string buttonPressed = "qrc:/img/XXPressed.png"
    5.  
    6. Button
    7. {
    8. image.source: mousearea.pressed ? parent.buttonPressed : parent.buttonStd
    9. mousearea.onClicked
    10. {
    11. parent.buttonStd = "qrc:/img/YY.png"
    12. parent.buttonPressed = "qrc:/img/YYPressed.png"
    13. }
    14. }
    15. }
    To copy to clipboard, switch view to plain text mode 
    What is interesting is, that I can use property binding in this case, but I can't use it in the onClicked scope right under the image.source binding (see posts above)... Is that because onClicked is a JavaScript functionallity and there is no property binding allowed but instead value assignment??

  10. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Changing background of every instance of a QML component (button)

    Quote Originally Posted by Binary91 View Post
    Ah, that sounds interesting! How does it look the other way round? How "big" is the id scope of a *.qml file other than the main.qml? I mean, when I'm right, all objects in a specific *.qml file can access each other by its id, but a "inter-qml-file-access" via id isn't possible? (except the "global" ones defined in main.qml)? So the id scope is limited to the qml file, right?
    I think all ids of "higher" files are visible.
    But I would recommend not to rely on that and use only id values defined with a file.
    Otherwise the code in a file becomes dependent on where it is being used from.

    Quote Originally Posted by Binary91 View Post
    I also found a third way for my purpose, I just placed the url properties to the button's parent object and bound the image source not directly in the specific component file but after creating the instances in main.qml, like that:
    Qt Code:
    1. Rectangle
    2. {
    3. property string buttonStd = "qrc:/img/XX.png"
    4. property string buttonPressed = "qrc:/img/XXPressed.png"
    5.  
    6. Button
    7. {
    8. image.source: mousearea.pressed ? parent.buttonPressed : parent.buttonStd
    9. mousearea.onClicked
    10. {
    11. parent.buttonStd = "qrc:/img/YY.png"
    12. parent.buttonPressed = "qrc:/img/YYPressed.png"
    13. }
    14. }
    15. }
    To copy to clipboard, switch view to plain text mode 
    So all your buttons have the same parent?

    Quote Originally Posted by Binary91 View Post
    What is interesting is, that I can use property binding in this case, but I can't use it in the onClicked scope right under the image.source binding (see posts above)... Is that because onClicked is a JavaScript functionallity and there is no property binding allowed but instead value assignment??
    I am afraid I don't understand the question.
    Your snippet above never replaces any binding.

    Cheers,
    _

  11. #11
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Re: Changing background of every instance of a QML component (button)

    So all your buttons have the same parent?
    Yes, exactly, but it should also work with an object other than parent when it is also located in the main file and has a id to call it...

    I am afraid I don't understand the question.
    Your snippet above never replaces any binding.
    Ok, I'll try it again. The code above uses a property binding (image.source: parent.buttonSdt). As you may remember from a few posts earlier, I asked you how I can use property binding outside of the "declaration" of the component.
    In my example earlier, I could not use property binding like I wanted to (QtCreator gave me errors), and so I used assignment (image.source = ...). You explained the difference to me and told me why this would overwrite every earlier binding...
    Now, I use property binding outside of the component declaration and QtCreator doesn't give me an error. I'll explain it with some code:
    Qt Code:
    1. //Button.qml
    2. Rectangle
    3. {
    4. width: 90
    5. height: 30
    6. color: "transparent"
    7.  
    8. property alias image: image
    9. property alias mousearea: mousearea
    10. property alias text: text.text
    11.  
    12. BorderImage
    13. {
    14. id: image
    15. width: parent.width
    16. height: parent.height
    17. border { left: 25; top: 25; right: 25; bottom: 25 }
    18. horizontalTileMode: BorderImage.Stretch
    19. verticalTileMode: BorderImage.Round
    20. }
    21.  
    22. MouseArea
    23. {
    24. id: mousearea
    25. anchors.fill: parent
    26. acceptedButtons: Qt.LeftButton
    27. cursorShape: "PointingHandCursor"
    28. }
    29.  
    30. Text
    31. {
    32. id: text
    33. anchors.centerIn: parent
    34. color: "white"
    35. font.bold: true
    36. }
    37. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. //main.qml
    2. Button
    3. {
    4. // no errors when I make a binding here:
    5. image.source: mousearea.pressed ? parent.buttonPressed : parent.buttonStd
    6. mousearea.onClicked:
    7. {
    8. // if I placed binding right here, QtCreator would give me errors
    9. }
    10. }
    To copy to clipboard, switch view to plain text mode 
    Do you know now what I mean? A few posts earlier I asked you how to make bindings from outside, but I see now that it is possible within the object instance, but not within an onClicked scope... Do you know why?

  12. #12
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Changing background of every instance of a QML component (button)

    Quote Originally Posted by Binary91 View Post
    Yes, exactly, but it should also work with an object other than parent when it is also located in the main file and has a id to call it...
    Right, but then this is the other option I already mentioned above.

    Quote Originally Posted by Binary91 View Post
    Ok, I'll try it again. The code above uses a property binding (image.source: parent.buttonSdt).
    Yes, but you never change/overwrite that.

    Quote Originally Posted by Binary91 View Post
    As you may remember from a few posts earlier, I asked you how I can use property binding outside of the "declaration" of the component.
    Which turned out not to be necessary.

    Quote Originally Posted by Binary91 View Post
    In my example earlier, I could not use property binding like I wanted to (QtCreator gave me errors), and so I used assignment (image.source = ...). You explained the difference to me and told me why this would overwrite every earlier binding...
    Exactly.

    Quote Originally Posted by Binary91 View Post
    Now, I use property binding outside of the component declaration and QtCreator doesn't give me an error. I'll explain it with some code:
    Qt Code:
    1. //main.qml
    2. Button
    3. {
    4. // no errors when I make a binding here:
    5. image.source: mousearea.pressed ? parent.buttonPressed : parent.buttonStd
    6. mousearea.onClicked:
    7. {
    8. // if I placed binding right here, QtCreator would give me errors
    9. }
    10. }
    To copy to clipboard, switch view to plain text mode 
    Just a normal property binding within the instantiation of the component, as usual.
    No overwriting of any binding during runtime.

    Quote Originally Posted by Binary91 View Post
    Do you know now what I mean? A few posts earlier I asked you how to make bindings from outside, but I see now that it is possible within the object instance, but not within an onClicked scope... Do you know why?
    (a) I've mentioned how to assign a new property binding
    (b) it is not necessary at all since you only need to change values of reference properties
    (c) a property binding is a binding no matter in which file you do it. There is no difference between it being in Button.qml or in whereever Button is being used, other than one applying to all instance of Button and the other only applying to the one.

    Cheers,
    _

  13. The following user says thank you to anda_skoa for this useful post:

    Binary91 (27th December 2014)

  14. #13
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Re: Changing background of every instance of a QML component (button)

    Ok, I see I have to get much more experience in that stuff and I need to get used to it by coding... I was just wondering why I can't use property binding in a javascript statement like onClicked: {}, although it is in the instanciating part of the component...

    Well, thank you one more time for spending time explaining that stuff to me, I appreciate that! :-)

    Cheers,

  15. #14
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Changing background of every instance of a QML component (button)

    Quote Originally Posted by Binary91 View Post
    I was just wondering why I can't use property binding in a javascript statement like onClicked: {}, although it is in the instanciating part of the component...
    You can use property binding there using Qt.bind(). You cannot use the colon syntax because it is not a valid javascript statement.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  16. #15
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Changing background of every instance of a QML component (button)

    Quote Originally Posted by Binary91 View Post
    I was just wondering why I can't use property binding in a javascript statement like onClicked: {}
    I think I provided a link on how to do that in comment #6.

    Cheers,
    _

  17. #16
    Join Date
    Nov 2014
    Location
    Germany
    Posts
    69
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Windows Android

    Default Re: Changing background of every instance of a QML component (button)

    I think I provided a link on how to do that in comment #6.

    Cheers,
    Yep, you're right, thank's again.

    You cannot use the colon syntax because it is not a valid javascript statement.
    This is exactly what I wanted to hear I was not sure about it, but now I know it, so QML implements javascript without manipulating anything of its syntax I guess... That is good to know. I'm still confused about how that whole stuff is compiled when I'm using three different "languages".. I will google that to get more information about it.

    Thank you for your time

    Greetings

Similar Threads

  1. Replies: 0
    Last Post: 5th January 2013, 14:29
  2. changing button background color
    By Tomasz in forum Newbie
    Replies: 4
    Last Post: 27th November 2010, 05:09
  3. Changing text of button in no relation to button
    By Sabre Runner in forum Newbie
    Replies: 22
    Last Post: 23rd September 2010, 13:29
  4. changing the background for a tablewidget
    By qtlinuxnewbie in forum Newbie
    Replies: 4
    Last Post: 27th February 2010, 06:02
  5. Changing the background of QTabWidget
    By ike in forum Qt Tools
    Replies: 2
    Last Post: 7th November 2008, 14:43

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.