Android Question Problem with Checkbox(or Switch)

wes58

Active Member
Licensed User
Longtime User
I have in my application a number of checkboxes. The checkbox state can be changed either by clicking on tje checkbox or changing its state by code (checkbox.Checked = True/False).
The problem I have, is that both, a click on a checkbox and changing state by code trigger Sub cb1_CheckedChange(Checked As Boolean).
What I expected to see (and what I need) is that Sub cb1_CheckedChange(Checked As Boolean) is only triggered when I click on the checkbox.
When I change the state of the checkbox by code, I only want to change the state of the checkbox, but not trigger the event - because I didn't click on the checkbox.

To demonstrate this, I created a project with the following code:

B4X:
Private cb1 As CheckBox
Private sw1 As ACSwitch
Private textView As Label

Sub cb1_CheckedChange(Checked As Boolean)
    If Checked Then
        ToastMessageShow("Checkbox checked", True)
        textView.Text = "Checkbox Checked"
        Log("Checkbox Checked")
    Else
        ToastMessageShow("Checkbox not checked", True)   
        textView.Text = "Checkbox not Checked"
        Log("Checkbox Not Checked")
    End If
End Sub

Sub sw1_CheckedChange(Checked As Boolean)
    If Checked Then
        ToastMessageShow("Swich On", True)
        Log("Switch On, Checkbox set to Checked")
        Log("-----------------------------")
        cb1.Checked = True
Else
        ToastMessageShow("Switch Off", True)
        Log("Switch Off, Checkbox set to not Checked")
        Log("-----------------------------")
        cb1.Checked = False
    End If
End Sub

Here is the log of the events when the Switch is clicked to simulate change the state of the checkbox by code:

B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **

Switch On, Checkbox set to Checked
-----------------------------
Checkbox Checked
Switch Off, Checkbox set to not Checked
-----------------------------
Checkbox Not Checked

I don't want to see an event being triggered "Checkbox Checked"/"Checkbox not Checked" in this situation.

I thought that maybe it is a normal Android behaviour, so I created a simple project in Android Studio with the same type of controls.
Relevant part of the java code is here:
B4X:
@Override
    public void onClick(View view) {

        switch (view.getId()) {
            case R.id.cb1:
                if(checkBox.isChecked()){
                    Toast.makeText(getApplicationContext(), "checkbox checked", Toast.LENGTH_LONG).show();
                    textView.setText("Checkbox Checked");
                    Log.d("B4A", "CheckBox Checked");
                }
                else{
                    Toast.makeText(getApplicationContext(), "checkbox not checked", Toast.LENGTH_LONG).show();
                    textView.setText("Checkbox not Checked");
                    Log.d("B4A", "CheckBox not Checked");
                }
                break;
            case  R.id.sw1:
                if(aSwitch.isChecked()){
                    Toast.makeText(getApplicationContext(), "switch On", Toast.LENGTH_LONG).show();
                    checkBox.setChecked(true);
                    Log.d("B4A","Switch On, Checkbox set to Checked");

                }
                else{
                    Toast.makeText(getApplicationContext(), "switch Off", Toast.LENGTH_LONG).show();
                    checkBox.setChecked(false);
                    Log.d("B4A","Switch Off, Checkbox set to not Checked");
                }
        }
    }

And here is the log of the events when the switch is clicked:
B4X:
Switch On, Checkbox set to Checked
Switch Off, Checkbox set to not Checked
The checkbox is activated, but no click event is registered when the state is changed by code (by clicking on a switch)
So, Android behaviour is what I have expected to be, and what I need.


Why is the B4A different?
Can I do it in B4A?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
The checked changed event is raised by an OnCheckedChangeListener (I'm not sure that onClick will be raised in all cases but it is less important).

You can use these two subs to ignore the unwanted events. Set the EventName of all CheckBoxes to be the same and use Sender keyword to find the CheckBox that raised the event.
B4X:
Sub Activity_Click
   SetCheckedWithoutEvent(CheckBox1, Not(CheckBox1.Checked))   
End Sub

Sub SetCheckedWithoutEvent (chk As CheckBox, Value As Boolean)
   If chk.Checked = Value Then Return
   IgnoreCheckedEvent (chk)
   chk.Checked = Value
End Sub

Sub IgnoreCheckedEvent(chk As CheckBox)
   Wait For (chk) CheckBox1_CheckedChange(Checked As Boolean)
   Log("event ignored")
End Sub

Sub CheckBox1_CheckedChange(Checked As Boolean)
   Log("User changed the state to: " & Checked)
End Sub
 
Upvote 0

wes58

Active Member
Licensed User
Longtime User
The checked changed event is raised by an OnCheckedChangeListener (I'm not sure that onClick will be raised in all cases but it is less important).

You can use these two subs to ignore the unwanted events. Set the EventName of all CheckBoxes to be the same and use Sender keyword to find the CheckBox that raised the event.
B4X:
Sub Activity_Click
   SetCheckedWithoutEvent(CheckBox1, Not(CheckBox1.Checked))  
End Sub

Sub SetCheckedWithoutEvent (chk As CheckBox, Value As Boolean)
   If chk.Checked = Value Then Return
   IgnoreCheckedEvent (chk)
   chk.Checked = Value
End Sub

Sub IgnoreCheckedEvent(chk As CheckBox)
   Wait For (chk) CheckBox1_CheckedChange(Checked As Boolean)
   Log("event ignored")
End Sub

Sub CheckBox1_CheckedChange(Checked As Boolean)
   Log("User changed the state to: " & Checked)
End Sub
Thanks for your reply. I will try that.
Although it complicates a simple thing. Especially, that I have 8 checkboxes. Each of them represent one bit of the byte. I set the checkboxes by code when I receive and decode a byte of configuration data. And I encode the state of the checkboxes (changed manually by clicking on them) and send the byte to configure the device.

When you look on this page https://developer.android.com/guide/topics/ui/controls/checkbox#java they write:
Responding to Click Events
When the user selects a checkbox, the CheckBox object receives an on-click event.

To define the click event handler for a checkbox, add the android:eek:nClick attribute to the <CheckBox> element in your XML layout. The value for this attribute must be the name of the method you want to call in response to a click event. The Activity hosting the layout must then implement the corresponding method.
I could understand, that there might be a problem with a switch, when instead of clicking on the switch you drag it. But there is no such problem with a checkbox.
 
Upvote 0

wes58

Active Member
Licensed User
Longtime User
Don't create 8 events. Use the Tag property to store any information needed and handle them all with a single event.
Yes, that's what I have been doing. I just have to think how to do it using your example.
 
Upvote 0

wes58

Active Member
Licensed User
Longtime User
Exactly the same. You just need to call SetCheckedWithoutEvent instead of setting CheckBox.Checked.
I found an easier solution.
I have decided to check, if there is a Click event raised, so I created a Sub cb1_Click (for checkbox) and sw1_Click for ACSwitch, and both work, registering a click event on a checkbox/ACSwitch and ignoring it when the state is changed by code.
I think that this event might be inherited from a view events.

So Checkbox and ACSwitch have two events
B4X:
'ACSwitch
Sub switch_Click
'sub ignored when state changed by code
'registering only click event
End Sub

Sub switch_CheckedChange(Checked As Boolean)
'registering when state changed by code
'and registering the click event
End Sub

'Checkbox
Sub checkbox_Click
'sub ignored when state changed by code
'registering only click event
End Sub

Sub checkbox_CheckedChange(Checked As Boolean)
'registering when state changed by code
'and registering the click event
End Sub
 
Upvote 0
Top