0023: Radio and Color Selection Buttons

RadioButtons are complex and tricky suckers and if you don’t prep their bits and pieces in just the right order, they aren’t going to work. ColorButtons? Not so much, but to harness a ColorButton to do our bidding means we’ll use a signal found in no other widget.

Put Your RadioButton On

Results of this example:
Current example output
Current example output
Current example terminal output
Current example terminal output (click for enlarged view)

As with so many other widgets, stuffing a set of RadioButtons into a Box makes good sense. At the design stage, you can move that Box around easily and take all the RadioButtons along with no fuss. And we already know the advantages of Boxes at runtime, but if you don’t remember, it gives us a place from which to observe and manipulate them.

So, let’s look at the RadioBox, a child class born of the Box:

class RadioBox : Box
	int padding = 5;
	Observed observed = new Observed(null);
	MyRadioButton button1, button2, button3;
	ActionButton actionButton;
		super(Orientation.VERTICAL, padding);
		button1 = new MyRadioButton("button 1", observed);
		button2 = new MyRadioButton("button 2", observed);
		button3 = new MyRadioButton("button 3", observed);

		actionButton = new ActionButton(observed);
	} // this()
	void setActiveButton(Button button)
		// set which button is active on start-up
		observed.setState(button2.getLabel()); // initial state
		button2.setActive(true);  // set AFTER all buttons are instantiated
	} // setActiveButton()

} // class Radiobox

RadioBox: An Observation Point

First thing of note is that we’re once again using an Observed class. If you think about it, there’s not much point in having a set of RadioButtons if they aren’t affecting some entity that is, in turn, being observed by some other entity. Here, the RadioButtons affect an Observed object and the ActionButton acts as observer, modifying its behaviour based on what it sees.

RadioButton Creation

The first RadioButton is easy, just create it, give it a name, etc., and you’re done. But with the second RadioButton in the set, that’s where you need to know the tricky bit.

Yes, we simply create button2, but then we need to tell it that it’s in the same Group as button1. But the Group doesn’t exist, and can’t exist, before button1 is created. Even then, the only way to find the Group and tell button2 about it is to get it from button1.

But once you know that, adding button3 or other subsequent buttons is dead easy again.

RadioButton State

If we don’t care which RadioButton is active, all we have to do is sync up the state of the observed object so it points at the default active RadioButton and that’s always going to be the first one created, button1 in this example.

But if we want one of the others to be active on start-up, as well as syncing up the observed object, we have to call that button’s setActive(true) function. To simplify this two-step process, I broke it out into its own function, setActiveButton().

And one more note about this: Don’t try to set state or setActive() until all the buttons are created. Your results may be unpredictable.

MyRadioButton Class

Familiar territory, this. Hook up the observed object, attach a signal and we’re ready to go.

One thing of note: Because we’re using the onToggle signal, we have to declare our RadioButton as a ToggleButton or we’ll get an error. This works because RadioButton is a grandchild of ToggleButton (with CheckButton being in the middle of the hierarchy). In effect, we’re borrowing grandma’s signal. If we try to do this any other way, casting the button as a RadioButton (or as its parent, a CheckButton) won’t work because the onToggle() delegate can only take a ToggleButton as its argument.

ActionButton and Observed class

Same as with the MyRadioButton, we’ve seen all this before. At least, we’ve seen stuff like it.

So, let’s move on to our next subject…

A ColorButton to Select Color

Results of this example:
Current example output
Current example output
Current example terminal output
Current example terminal output (click for enlarged view)

The similarities between this example and the previous one won’t be lost on you. Instead of a RadioBox, we’ve got a ColorBox and in it:

  • a similar Observed object,
  • a FetchColorButton to fetch,
  • a ResetColorButton to reset the color to its default, and
  • an array to hold them all.

And everything else is stuff we’ve seen before. A quick browser through the code will get you up to speed as long as you’ve been following these blog posts in order and haven’t jumped straight here.

There are two places where notable differences show up. One is in the construction of the ObservedColor class:

class ObservedColor                                                             // *** NOTE *** r, g, b, a = 0.00 - 1.0
	string message = "Color is now ";
	RGBA color;
	RGBA defaultColor;
	float red = .75, green = .75, blue = .75, alpha = 1.0;
		defaultColor = new RGBA(red, green, blue, alpha);
	} // this()
	void setColor(RGBA extColor)
		color = extColor;
		writeln(message, extColor);

	} // setColor()

	RGBA getColor()
	} // getColor()

} // class ObservedColor

In earlier Observed objects, we used strings to keep track of state, but here we’re storing the actual RGBA objects themselves (ie. the colors) within the Observed object. This gives us a central location to store colors that’s accessible to any object in the ColorBox.

And if we want to add a second color (perhaps we want a foreground color and a background color a la Photoshop) we simply add a second ColorBox, label the two ColorBoxes as Foreground and Background, and we’re set.

Of course, you’d likely want to be a little slicker with the UI design, but this gives you a place from which to leap off the cliff.

And so we wrap up another gtkDcoding blog post with this: May your bugs only nip you a bit, and not byte.

Comments? Questions? Observations?

Did we miss a tidbit of information that would make this post even more informative? Let's talk about it in the comments.

You can also subscribe via RSS so you won't miss anything. Thank you very much for dropping by.

© Copyright 2023 Ron Tarrant