Results 1 to 16 of 16

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

Hybrid View

Previous Post Previous Post   Next Post Next Post
  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?

Similar Threads

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