Why do it?

Radio buttons are graphical elements that present users with a choice between multiple options. By convention, users can only select one radio button at a time, so they are added to a UI when users are allowed to choose only one option.

Lucy also represents user choices with radio buttons. For example, in the Lucy menu you use radio buttons to select a formatting option for the unit of speed. Lucy sets the formatting of the speed unit for the entire application, so only one format can be active at a time. You can display speed in kilometers per hour (km/h), in meters per second (m/s), or in other units.

speed menu
Figure 1. Speed unit selection radio buttons in the Lucy menu

How to do it?

Adding radio buttons to the UI can be done by creating and inserting ILcyActiveSettable implementations. You must however take care of two things:

  1. Make sure that the ILcyActiveSettable instances can de-activate themselves. For example, when the default speed format is changed to m/s, the km/h active settable must become inactive.

    Example: Active settable implementation to change the speed format.
    When your ILcyActiveSettable objects are represented by radio buttons, their "state" is typically stored outside the active settables. In the speed unit selection example, the active settable state is the speed format stored at the Lucy back-end. Our m/s active settable is considered to be active when the speed format at the back-end formats speeds in m/s, and is considered inactive when the speed format on the Lucy back-end uses a different formatting.

    Whenever the speed format changes at the Lucy back-end, the back-end fires an event. Our active settables need to listen for those events, and de-activate if necessary. This is what an example implementation of such an ILcyActiveSettable could look like:

    ILcyActiveSettable implementation to change the speed format
    public class SpeedFormatActiveSettable extends ALcyActiveSettable{
    
      private final TLcdSpeedFormat fFormat;
      private final ILcyLucyEnv fLucyEnv;
    
      public SpeedFormatActiveSettable(TLcdSpeedFormat aFormat, ILcyLucyEnv aLucyEnv) {
        fFormat = aFormat;
        fLucyEnv = aLucyEnv;
        fLucyEnv.addPropertyChangeListener(new SpeedFormatListener(this));
      }
    
      @Override
      public boolean isActive() {
        return fLucyEnv.getDefaultSpeedFormat() == fFormat;
      }
    
      @Override
      public void setActive(boolean aActive) {
        if ( aActive ){
          fLucyEnv.setDefaultSpeedFormat(fFormat);
        }
        // do nothing when !aActive
        // this active settable can only be activated, not de-activated
        // de-activation happens automatically when the speed format on the back-end changes
      }
    
      /**
       * Each time the default format at the Lucy back-end changes, we need to see whether the "active"
       * state of our active settable changed, and fire an event if needed.
       */
      private static class SpeedFormatListener extends ALcdWeakPropertyChangeListener<SpeedFormatActiveSettable>{
    
        public SpeedFormatListener(SpeedFormatActiveSettable aObjectToModify) {
          super(aObjectToModify);
        }
    
        @Override
        protected void propertyChangeImpl(SpeedFormatActiveSettable aActiveSettable, PropertyChangeEvent aPropertyChangeEvent) {
          if ("defaultSpeedFormat".equals(aPropertyChangeEvent.getPropertyName()) ){
            aActiveSettable.firePropertyChange("active",
                                         aPropertyChangeEvent.getOldValue() == aActiveSettable.fFormat,
                                         aActiveSettable.isActive());
          }
        }
      }
    }

    Note that:

    • The active state of the ILcyActiveSettable is not stored inside the active settable. Instead, it is determined by comparing the current speed format at the Lucy back-end with the fFormat field in the active settable. The active settable is considered to be active when those two java.text.Format instances match.

    • When the active settable is activated, by a user clicking the radio button for example, fFormat will be set as the d default speed format at the back-end.

    • The SpeedFormatListener class is responsible for listening to change events in the speed format at the back-end. It transforms those events into PropertyChangeEvent instances for the active state of the ILcyActiveSettable. That way we make sure that the changes in the active state of the ILcyActiveSettable are correctly communicated to all listeners.

    • The setActive method only allows activating the ILcyActiveSettable. Calling setActive( false ) has no effect. Normally there is never any need to make such a call, because de-activating the active settable happens by clicking the radio button of another active settable.

  2. When you insert the active settable, specify that it should look like a radio button. You must do that explicitly, because there is nothing on the ILcyActiveSettable interface that distinguishes radio button active settables from regular active settables. You can indicate that an active settable is a radio button through the TLcyActionBarUtil#insertInConfiguredActionBars(ILcyActiveSettable, Object, TLcyActionBarManager, ALcyProperties, boolean) method. If the last boolean parameter is set to false, the action bar will style the UI element as a radio button.

    Example: Inserting the speed format active settables
    SpeedFormatActiveSettable kmH = new SpeedFormatActiveSettable(new TLcdSpeedFormat(TLcdSpeedUnit.KmH), aLucyEnv);
    kmH.putValue(TLcyActionBarUtil.ID_KEY, "SpeedFormatAddOn.kmhActiveSettable");
    // By using false as last parameter, the UI will use a radio button
    TLcyActionBarUtil.insertInConfiguredActionBars(kmH, null, actionBarManager, getPreferences(), false);
    
    SpeedFormatActiveSettable ms = new SpeedFormatActiveSettable(new TLcdSpeedFormat(TLcdSpeedUnit.MS), aLucyEnv);
    ms.putValue(TLcyActionBarUtil.ID_KEY, "SpeedFormatAddOn.msActiveSettable");
    // By using false as last parameter, the UI will use a radio button
    TLcyActionBarUtil.insertInConfiguredActionBars(ms, null, actionBarManager, getPreferences(), false )

You don’t always need to go through the API to customize Lucy tool bars. You can set up many commonly needed tool bar changes through the Lucy configuration files. For more information, see the available action bar configuration options.