1. Computing

Generic Solution to Coloring the Focused Entry Control

OnEnter + OnExit := Wrong Way!

By

Generic Solution to Coloring the Focused Entry Control

By (Windows) design, the control on a data entry form that has the input focus is not "drawn" differently from other controls (i.e. those without the input focus). In case of the TEdit control, only the blinking insertion point is displayed.

To provide visually more attractive user-friendly interfaces for your Delphi applications, you could decide to change the background color (and maybe some other properties) of the currently selected control - the control that has the input focus.
Of course, restoring to the original background color when the focus shifts to another control is also required.

OnEnter + OnExit := "Wrong Way"!

All Delphi controls that can receive the input focus (those derived from the base TWinControl class) expose the OnEnter and OnExit events. The OnEnter is fired when a control receives the input focus, OnExit is fired when the input focus shifts away from the current control to another.

Naturally, the first idea you got is to use the OnEnter and OnExit events of a control to change the Color property to "focused color" in the OnEnter event and restore the "original color" in the OnExit event.

Since Delphi controls can share event handlers, you could decide to write two common procedures to handle OnEnter and OnExit events for all the data entry controls on a form.

Let's say you have a TEdit ("Edit1"), a TMemo ("Memo1") and a TComboBox ("ComboBox1") on a form. If you set all those controls to share a common OnEnter and OnExit event handling procedures, your code would need to look something like:

"Bad Code Ahead" Warning!

 const
    focusedColor = clSkyBlue;
 var
    oldColor : TColor;
 
 procedure TMainForm.FormCreate(Sender: TObject) ;
 begin
    Button1.OnEnter := ControlOnEnter;
    ComboBox1.OnEnter := ControlOnEnter;
    Memo1.OnEnter := ControlOnEnter;
 
    Button1.OnExit := ControlOnExit;
    ComboBox1.OnExit := ControlOnExit;
    Memo1.OnExit := ControlOnExit;
 end;
 
 procedure TMainForm.ControlOnEnter(Sender: TObject) ;
 begin
    if Sender is TEdit then
    begin
      oldColor := TEdit(Sender).Color;
      TEdit(Sender).Color := focusedColor;
    end;
 
    if Sender is TComboBox then
    begin
      oldColor := TComboBox(Sender).Color;
      TComboBox(Sender).Color := focusedColor;
    end;
 
    //... other cases
 end;
 
 procedure TMainForm.ControlOnExit(Sender: TObject) ;
 begin
    if Sender is TEdit then
    begin
      TEdit(Sender).Color := oldColor;
    end;
 
    //... other cases
 end; 
Why is this approach far from ideal:
  • You lose the ability to handle the OnEnter and OnExit event on a control level - as Delphi (for Win32) does not support multicast events.
  • You cannot simply use "TWinControl(Sender).Color" as the Color property is not exposed by TWinControl - the class all input controls inherit from. The Color property comes from the TControl class as protected, controls make it public on their own.
  • As you drop more controls on the form, you have to make sure the correct class is already handled. For example, if you drop a TRadioButton, you need to add the code to check if the Sender is TRadioButton.
  • What if you want to provide such visuall feedback for all your data entry forms? No go!
So, what's the solution? How to handle those OnEnter and OnExit on a higher level?

The answer lies in using the TScreen's OnActiveControlChange event and Delphi's RTTI ... reveal the answer (and download the solution with source code) on the next page ...

©2014 About.com. All rights reserved.