Mixed-state checkboxes
Mixed-state checkboxes
- Subject: Mixed-state checkboxes
- From: Jonathan Taylor <email@hidden>
- Date: Fri, 08 Jul 2016 13:36:40 +0100
Hi all,
I'm trying to work out the correct way to handle a mixed-state checkbox (NSButton checkbox with allowsMixedState=YES), bound to a property on my controller. I am intending it to serve as an "applies to all" type control at the head of a column of checkboxes - so if other checkboxes in the column are toggled, it will display a state of on (if all in column are on), off (if all are off), or mixed if there is a mixture of states in the column.
My property has no backing variable, but a manually-implemented getter and setter. I am happy with how the getter is working - it scans the column and returns the appropriate state. What I am not sure about is how to handle the setter.
It seems that allowsMixedState makes it possible to *present* the mixed state, but also means that the user can click through the three states in order. What I believe the normal interface would be in my situation is for a user click on a box in on (or off) state to switch it to off (or on), and a click on mixed state puts it to either on or off (not sure which). What I would not expect is for a click when in off state to put it into MIXED state. In this interface (if I have described it clearly!) it makes no sense for the user to actively put the checkbox into mixed state.
So... my question is how to implement the correct behaviour?
1. It would be great if there was a flag I could set that says "behave like I want", but I can't see one!
2. Failing that, I believe what I need to do is to spot the setter being called with a value of -1 (mixed), and overrule that. However, I haven't found a way of doing that that "feels right" - all successful approaches feel like a hack rather than the right way of doing it. My setter code currently looks like this:
-(void)setGlobalChannelEnableState:(NSInteger)state
{
if (state == -1)
{
#if 0
// Checkbox remains in '-' state if I use this code
[self willChangeValueForKey:@"globalChannelEnableState"];
state = 1;
[self didChangeValueForKey:@"globalChannelEnableState"];
#elif 1
// Works. Schedule another call in a moment, to update the value to 'on'
dispatch_async(dispatch_get_main_queue(), ^{ self.globalChannelEnableState = 1; });
return;
#else
// Also works. Change the input state and fall through to the code that does the actual updating (below)
state = 1;
dispatch_async(dispatch_get_main_queue(),
^{
[self willChangeValueForKey:@"globalChannelEnableState"];
[self didChangeValueForKey:@"globalChannelEnableState"];
});
#endif
}
// Update state for all individual channels [code not shown here]
}
Can anybody comment, and maybe suggest a more elegant way of handling this? For brevity, I have not shown the getter code, but remember that there is no backing variable and the getter just examines the current program state to determine what the correct value is.
Thanks for any comments
Jonny.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden