1. Technology
Send to a Friend via Email
Implementing OnMouseOver for Items in a TComboBox, with custom hints.
Here's how to get the caption of an item in a TComboBox as mouse hovers over an item when the ComboBox is in drop down state. Use this "trick" to get the object associated with the "pre-selected" item in a combo box, or to display a custom hint for each item, for example.
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 More of this Feature
• FULL SOURCE CODE
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• Using VCL component
• VCL tricks
• Message handling
• TListBox to the MAX
• Using Windows API
• Custom hint windows

When a TComboBox is in drop down state, and you move around the items with mouse, the item the mouse is over is "pre-selected" (colored in "clHighLight" color). If you ever wanted to get the text of that "pre-selected" item (to show a hint for this item, for example), you probably noticed that such a property does not exist.

When a combo box is dropped down, its Items are displayed in a list box type of control. The VCL TListBox component does actually provide an OnMouseOver event, yet, this event will not fire for TComboBox's list box since the list box part of the combobox is not a VCL control.

If you were lucky and the TComboBox's list box was TListBox, than you will have no problems to "get ListBox items as mouse hovers over them".
However, if you need to know what TComboBox item is "pre-selected", you'll need a little trick...

TComboBox.Items OnMouseMove
TComboBox item textIn order to get the text of the combo box item "under" the mouse, when the combo is in drop down state, you need to send some specific messages to the actual list box displayed. Your best bet is to place the code in the Application.OnIdle event handler since this event is fired when it is waiting for input from the user (not processing application's code).

The code provided below is an example of how to get the name of the combo box and the text of the item the mouse hovers over. Firstly, we get the handle of the window under the mouse (WindowFromPoint), we check if the window is a combo box (GetClassName). Secondly, we get the index of the "pre-selected" item (by sending the LB_ITEMFROMPOINT message to the underlying list box). Next, if we have a valid item index, we get the text of the item by sending the LB_GETTEXT message. Finally, the combo box name and the item text are displayed in a TLabel component.

procedure TForm1.ApplicationIdle(
sender: TObject; var Done: boolean);
var
  pt         : TPoint;
  w          : Hwnd;
  ItemBuffer : array[0..256] of Char;
  idx        : Integer;
  s          : string;
begin
  pt := Mouse.CursorPos;
  w := WindowFromPoint(pt);
  if w = 0 then Exit;

  GetClassName(w, ItemBuffer, SizeOf(ItemBuffer));
  if StrIComp(ItemBuffer, 'ComboLBox') = 0 then
  begin
    Windows.ScreenToClient(w, pt);
    idx := SendMessage(w,
                       LB_ITEMFROMPOINT,
                       0,
                       LParam(PointToSmallPoint(pt)));
    if idx >= 0 then
    begin
      if LB_ERR <> SendMessage(w,
                               LB_GETTEXT,
                               idx,
                               LParam(@ItemBuffer)) then
      begin
        s:= 'Mouse over item: ' + #13#10 +
            Format('Combo.Name: %s,%sItem.Text: %s',
                  [ActiveControl.Name,#13#10,ItemBuffer]);

        ComboItemLabel.Caption := s;
        
        //explained  later
        hw.DoActivateHint(ActiveControl.Name + ItemBuffer, 
                          'Hint for: ' + ItemBuffer);
      end;
    end;
  end;
end; (*ApplicationIdle*)

That's it. Tricky yet simple.

In the sample application provided for download, there's also code that "activates" the ApplicationIdle procedure when the combo box fires its OnDropDown event; similary the Application.OnIdle is set to nil when the combo box fires the OnCloseUp event.

TComboBox.Item custom hint messages
As you can see from the screen shot, you can attach custom hint text for each combo box item. In general, a class TComboItemHint that derives from THintWindow is used to display custom hint messages for each item. The DoActivateHint procedure calls the ActivateHint method of the THintWindow. ActivateHint displays the hint window at the specified coordinates (where the mouse is).

type
  TComboItemHint = class(THintWindow)
  private
    DoHint : boolean;

    FControlName: string;
    procedure SetControlName(const Value: string);
    private
      property ControlName : string 
               read FControlName write SetControlName;
    public
    procedure DoActivateHint(
              ControlName : string; Text : string);
  end;
  
 ...
procedure TComboItemHint.DoActivateHint(
ControlName : string; Text: string);
var
  pt : TPoint;
  r : TRect;
begin
  self.ControlName := ControlName;
  if DoHint then
  begin
    pt := Mouse.CursorPos;

    //some hard-coding
    r:= Rect(pt.X + 16,
             pt.Y + 16,
             pt.X + 100,
             pt.Y + 32);

    ActivateHint(r,Text);
    DoHint := false;
  end;
end;

procedure TComboItemHint.SetControlName(
const Value: string);
begin
  if FControlName <> Value then
  begin
    ReleaseHandle;
    //remove flicker
    DoHint := True;
    FControlName := Value;
  end;
end; 

©2014 About.com. All rights reserved.