7

I have a simple list of CheckBoxes, one for each day of the week. They depend on the value of days, an integer using a mask, 1 bit for each CheckBox.

Assigning to days both with the "clear all" button or the "set all" button works and they update. However, once any of the boxes have been clicked, they no longer respond to changes in the dependent property days.

Why is this? Are they somehow becoming unbound. If so, should i be manually re-binding them, and if so why?

Here's the code,

import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3

ApplicationWindow
{
    visible: true
    width: 800
    height: 400

    property int days: 0

    ColumnLayout
    {
        Repeater
        {
            model: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
            CheckBox
            {
                text: modelData
                checked: (days & (1<<index)) != false
                onClicked:
                {
                    if (checked) days |= (1<<index);
                    else days &= ~(1<<index);
                }

            }
        }

        Button 
        {
            text: "clear all"
            onClicked: days = 0
        }

        Button 
        {
            text: "set all"
            onClicked: days = 127
        }
    }
}

which looks like this:

enter image description here

To reproduce the problem, first click on "set all" and "clear all". then click on some checkboxes. Then click on "set all" and "clear all" again. You'll see that the boxes you checked are no longer affected.

thanks.

jpnurmi
  • 5,716
  • 2
  • 21
  • 37
jkj yuio
  • 2,543
  • 5
  • 32
  • 49

2 Answers2

3

OP here.

Selbie's answer is quite correct. But i'd like to post a variation that i prefer.

I have come to the conclusion that CheckBoxes are broken in QT. This is because you will want to bind them to your data model. and you will also want to click them (otherwise what's the point). Clicking on them breaks the connection to the model, so that it must be fixed up manually (see Selbie's answer). To me this a broken design.

My variation uses a Binding so that it doesn't have to be re-established every time you click.

like this:

import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3

ApplicationWindow
{
    visible: true
    width: 800
    height: 400

    property int days: 0

    ColumnLayout
    {
        Repeater
        {
            model: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
            CheckBox
            {
                text: modelData
                Binding on checked { value: (days & (1 << index)) != 0 }
                onClicked:
                {
                    if (checked) days |= (1<<index)
                    else days &= ~(1<<index)
                }
            }
        }

        Button 
        {
            text: "clear all"
            onClicked: days = 0
        }

        Button 
        {
            text: "set all"
            onClicked: days = 127
        }
    }
}

Posting this variation for the benefit of others.

jkj yuio
  • 2,543
  • 5
  • 32
  • 49
1

When you manually click the checkbox, the checked property gets reassigned to a hardcoded true instead of the original expression: (days & (1<<index)) != false. Likewise, a manual uncheck of the box forces the checked property to a hardcoded false.

The fix is to simply rebind the checked property using Qt.binding. I've cleaned up your javascript and fixed your bug. You are welcome.

    Repeater
    {
        model: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
        CheckBox
        {
            function isChecked() {
                return ((days & (1 << index)) != 0);
            }

            text: modelData
            checked: isChecked()
            onClicked:
            {
                if (checked) {
                    days |= (1<<index);
                }
                else {
                    days &= ~(1<<index);
                }

                // now rebind the item's checked property
                checked = Qt.binding(isChecked);

            }
        }
    }
selbie
  • 100,020
  • 15
  • 103
  • 173
  • Thanks very much! Your answer works a treat. I hadn't realised that assigning to `days` caused the dependency of `checked` to be broken. Thanks for the explanation. – jkj yuio Aug 06 '16 at 19:26
  • Assigning to `days` **does not** cause the `checked` property to be broken. The actual user click on the checkbox causes it to be broken. Think of it like this. Right before `onClicked` is called, Qt invokes `checked=true;` Thereby overriding your conditional. – selbie Aug 07 '16 at 07:51
  • Yes you're right, of course. it's done by the actual click. thanks for clarifying. – jkj yuio Aug 07 '16 at 21:06