Derived from: public BView
Declared in: <interface/Control.h>
BControl is an abstract class for views that draw control devices on the screen. Objects that inherit from BControl emulate, in software, real-world control devices--like the switches and levers on a machine, the check lists and blank lines on a form to fill out, or the dials and knobs on a home appliance.
Controls translate the messages that report generic mouse and keyboard events into other messages with more specific instructions for the application. A BControl object can be customized by setting the message it posts when invoked and the target object that should handle the message.
Controls also register a current value, stored as a long integer that's typically set to B_CONTROL_ON or B_CONTROL_OFF. The value is changed only by calling SetValue(), a virtual function that derived classes can implement to be notified of the change.
The Interface Kit currently includes six classes derived from BControl --BButton, BPictureButton, BRadioButton, BCheckBox, BColorControl, and BTextControl. In addition, it has two classes--BListView and BMenuItem--that implement control devices but are not derived from this class. BListView shares an interface with the BList class (of the Support Kit) and BMenuItem is designed to work with the other classes in the menu system.
As BListView and BMenuItem demonstrate, it's possible to implement a control device that's not a BControl. However, it's simpler to take advantage of the code that's already provided by the BControl class. That way you can keep a simple programming interface and avoid reimplementing functions that BControl has defined for you. If your application defines its own control devices--dials, sliders, selection lists, and the like-- they should be derived from BControl.
SetEnabled() | Enables and disables the control device; can be augmented by derived classes to note when the state of the object has changed. |
SetValue() | Changes the value of the control device; can be augmented to take collateral action when the change is made. |
BControl(BRect frame, const char *name, const char *label, BMessage *message, ulong resizingMode, ulong flags)
Initializes the BControl by setting its initial value to 0 ( B_CONTROL_OFF ), assigning it a label, and registering a model message that captures what the control does --the command it gives when it's invoked and the information that accompanies the command. The label and the message can each be NULL.
The label is copied, but the message is not. The BMessage object becomes the property of the BControl; it should not be deleted, posted, assigned to another object, or otherwise used in application code. The label and message can be altered after construction with the SetLabel() and SetMessage() functions.
The BControl class doesn't define a Draw() function to draw the label or a MouseDown() function to post the message. (It does define KeyDown(), but only to enable keyboard navigation between controls.) It's up to derived classes to determine how the label is drawn and how the message is to be used. Typically, when a BControl object needs to take action (in response to a click, for example), it calls the Invoke() function, which copies the model message and posts the copy so that it will be dispatched to the designated target. By default, the target is the window where the control is located, but SetTarget() can designate another handler.
Before posting a copy of the model message, Invoke() adds two data entries to it, under the names "when" and "source". These names should not be used for data items in the model.
The frame, name, resizingMode, and flags arguments are identical to those declared for the BView class and are passed unchanged to the BView constructor.
The BControl begins life enabled, and the Emily bitmap font is made the default font for all control devices.
See also: the BView constructor, BLooper::PostMessage() in the Application Kit, SetLabel(), SetMessage() , SetTarget(), Invoke()
virtual ~BControl(void)
Frees the model message and all memory allocated by the BControl.
virtual void AttachedToWindow(void)
Overrides BView's version of this function to make the BWindow to which the BControl has become attached the default target for the Invoke() function, provided that another target hasn't already been set. To designate the target, it calls SetTarget(), a virtual function.
AttachedToWindow() is called for you when the BControl becomes a child of a view already associated with the window.
See also: BView::AttachedToWindow(), BView::SetFontName(), Invoke() , SetTarget()
protected:
void Invoke(void)
Copies the BControl's model BMessage and posts the copy so that it will be dispatched to the designated target. The following two pieces of information are added to the copy before it's posted:
Data name | Type code | Description |
---|---|---|
"when" | B_DOUBLE_TYPE | When the control was invoked, as measured in microseconds from the time the machine was last booted. |
"source" | B_OBJECT_TYPE | A pointer to the BControl object. This permits the message handler to request more information from the source of the message. |
These two names shouldn't be used for data entries in the model.
If the control doesn't have a target BHandler, but it does have a designated BLooper where it can post the message, it will ask the BLooper for its preferred handler and name it as the target. Since the preferred handler for a BWindow object is the current focus view, this option allows control devices to be targeted to whatever view happens to be in focus at the time. See the SetTarget() function for information on how to designate a target BHandler and BLooper for the control.
Invoke() is designed to be called from the MouseDown() and KeyDown() functions defined for derived classes; it's not called for you in BControl code. It's up to each derived class to define what user actions trigger the call to Invoke() --what activity constitutes "invoking" the control.
This function doesn't check to make sure the BControl is currently enabled. Derived classes should make that determination before calling Invoke().
See also: SetTarget(), SetMessage(), SetEnabled()
virtual void KeyDown(ulong aChar)
Augments the BView version of KeyDown() to toggle the BControl's value and call Invoke() when aChar is the B_SPACE character or B_ENTER . This is done to facilitate keyboard navigation and make all derived control devices operable from the keyboard. Some derived classes--BCheckBox in particular--find this version of the function to be adequate. Others, like BRadioButton, reimplement it.
KeyDown() is called only when the BControl is the focus view in the active window. (However, if the window has a default button, B_ENTER events will be passed to that object and won't be dispatched to the focus view.)
See also: BView::KeyDown() , MakeFocus()
virtual void MakeFocus(bool focused = TRUE)
Augments the BView version of this function to call the BControl's Draw() function when the focus changes. This is done to aid keyboard navigation among control devices. If the Draw() function of a derived class has a section of code that checks whether the object is in focus and marks the on-screen display to show that it is (and removes any such marking when it isn't), the visual part of keyboard navigation will be taken care of. The derived class doesn't have to reimplement MakeFocus(). Most of the derived classes implemented in the Interface Kit depend on this version of the function.
See also: BView::MakeFocus(), KeyDown()
virtual void SetEnabled(bool enabled) bool IsEnabled(void) const
SetEnabled() enables the BControl if the enabled flag is TRUE, and disables it if enabled is FALSE. IsEnabled() returns whether or not the object is currently enabled. BControls are enabled by default.
While disabled, a BControl won't let the user navigate to it; the B_NAVIGABLE flag is turned off if enabled is FALSE and turned on again if enabled is TRUE.
Typically, a disabled BControl won't post messages or respond visually to mouse and keyboard manipulation. To indicate this nonfunctional state, the control device is displayed on-screen in subdued colors. However, it's left to each derived class to carry out this strategy in a way that's appropriate for the kind of control it implements. The BControl class merely marks an object as being enabled or disabled; none of its functions take the enabled state of the device into account.
Derived classes can augment SetEnabled() (override it) to take action when the control device becomes enabled or disabled. To be sure that SetEnabled() has been called to actually make a change, its current state should be checked before calling the inherited version of the function. For example:
void MyControl::SetEnabled(bool enabled) { if ( enabled == IsEnabled() ) return; BControl::SetEnabled(enabled); /* Code that responds to the change in state goes here. */ }
Note, however, that you don't have to override SetEnabled() just to update the on-screen display when the control becomes enabled or disabled. If the BControl is attached to a window, the Kit's version of SetEnabled() always calls the Draw() function. Therefore, the device on-screen will be updated automatically--as long as Draw() has been implemented to take the enabled state into account.
See also: the BControl constructor
virtual void SetLabel(const char *string) const char *Label(void) const
These functions set and return the label on a control device--the text that's displayed, for example, on top of a button or alongside a check box or radio button. The label is a null- terminated string.
SetLabel() makes a copy of string, replaces the current label with it, frees the old label, and updates the control on-screen so the new label will be displayed to the user --but only if the string that's passed differs from the current label. The label is first set by the constructor and can be modified thereafter by this function.
Label() returns the current label. The string it returns belongs to the BControl and may be altered or freed without notice.
See also: the BControl constructor, BView::AttachedToWindow(), BView::SetFontName()
virtual void SetMessage(BMessage *message) BMessage *Message(void) const ulong Command(void) const
SetMessage() sets the model BMessage that defines what the BControl does, and frees the message that was previously set. Message() returns a pointer to the BMessage that's the current model, and Command() returns its what data member. The message is first set by the BControl constructor.
Because Invoke() adds "when" and "source" entries to the messages it posts, these two names shouldn't be used for any data entries in the model BMessage.
The model message passed to SetMessage() and returned by Message() belongs to the BControl object; it can be modified in application code, but it shouldn't be deleted (except by passing NULL to SetMessage()), posted, or put to any other use.
See also: the BControl constructor, Invoke(), SetTarget()
virtual long SetTarget(BHandler *target) virtual long SetTarget(BLooper *looper, bool targetsPreferredHandler) BHandler *Target(BLooper **looper = NULL) const
These functions set and return the object that's targeted to handle the messages that the BControl posts (through its Invoke() function).
The version of SetTarget() that takes a single argument sets the target BHandler object. It's successful only if the target can reveal, through its Looper() function, a BLooper object where Invoke() can post messages so that they will be dispatched to that target. Therefore, the target BHandler must either:
Armed with both the BLooper and the target BHandler, Invoke() calls the BLooper's PostMessage() function and names the target as the object that should handle the message:
theLooper->PostMessage(theMessage, target);
After being set as the control's target, the BHandler must maintain its association with the BLooper. If it moves to another BLooper, PostMessage() will fail.
The version of SetTarget() that takes two arguments sets the BLooper object where the BControl's Invoke() function should post messages. If the targetsPreferredHandler flag is FALSE, messages will be targeted to the looper object itself--it will also act as the handler. In other words, passing a BLooper and FALSE to the version of SetTarget() that takes two arguments accomplishes the same thing as simply passing the BLooper alone to the version that takes one argument. These two lines of code accomplish the same thing:
myControl->SetTarget(someLooper, FALSE); myControl->SetTarget(someLooper);
The two-argument version of SetTarget() becomes interesting only if the targetsPreferredHandler flag is TRUE. In this case, messages are targeted to the looper's preferred handler (the object returned by its PreferredHandler() function). This permits the targeting decision to be made dynamically, at the time Invoke() is called:
looper->PostMessage(theMessage, looper->PreferredHandler());
For example, the preferred handler of a BWindow object is the current focus view. Therefore, by passing a BWindow looper and TRUE to SetTarget(),
myControl->SetTarget(someWindow, TRUE);
the control device can be targeted to whatever BView happens to be in focus at the time the control is invoked. This is useful for controls that act on the current selection. (Note, however, that if the PreferredHandler() is NULL, the looper itself becomes the target, just as it would if the targetsPreferredHandler flag were FALSE.)
When successful, SetTarget() returns B_NO_ERROR . It fails and returns B_BAD_VALUE if the proposed target or looper is NULL. The one-argument version also returns B_BAD_VALUE if it can't discover a BLooper from the target handler.
Target() returns the current target and, if a pointer to a looper is provided, fills in the BLooper where Invoke() will post messages. If the target BHandler is the preferred handler of the looper, Target() returns NULL . In other words, passing a BLooper and TRUE to SetTarget() causes Target() to report that there is a looper , but a NULL target--the BLooper is known, but the BHandler is not. Passing a BLooper and FALSE to SetTarget() causes Target() to report that the same object is both looper and target.
By default (established by AttachedToWindow() ), both roles--BLooper and BHandler--are filled by the BWindow where the control device is located.
See also: BHandler::Looper() and BLooper::PreferredHandler() in the Application Kit, BWindow::PreferredHandler(), Invoke() , AttachedToWindow()
virtual void SetValue(long value) long Value(void) const
These functions set and return the value of the BControl object.
SetValue() assigns the object a new value. If the value passed is in fact different from the BControl's current value, this function calls the object's Draw() function so that the new value will be reflected in what the user sees on-screen; otherwise it does nothing.
Value() returns the current value.
Classes derived from BControl should call SetValue() to change the value of the control device in response to user actions. The derived classes defined in the Be software kits change values only by calling this function.
Since SetValue() is a virtual function, you can override it to take note whenever a control's value changes. However, if you want your code to act only when the value actually changes, you must check to be sure the new value doesn't match the old before calling the inherited version of the function. For example:
void MyControl::SetValue(long value) { if ( value != Value() ) { BControl::SetValue(value); /* MyControl's additions to SetValue() go here */ } }
Remember that the BControl version of SetValue() does nothing unless the new value differs from the old.
The Be Book, HTML Edition, for Developer Release 8 of the Be Operating System.
Copyright © 1996 Be, Inc. All rights reserved.
Be, the Be logo, BeBox, BeOS, BeWare, and GeekPort are trademarks of Be, Inc.
Last modified September 6, 1996.