Title: Changing combo box
Question: How to change combo box list
Answer:
The Windows combo box contains a list box within it. In the standard combo box, this list box has exactly the same width as the combo box. However, you can make the width of the list box wider or narrower than the width of the combo box. And even you can change the position where this list box will appear. You may have seen combo box lists like this in Microsoft Word and Microsoft Excel. This article shows by example how to subclass standard combos box class to achieve this functionality.
The combo box in Windows is actually a combination of two or more controls; that's why it's called a "combo" box.
To change the combo box list appearance, you need the handle of the list box control within the combo box. This task is difficult because the list box is actually a child of the desktop window (for CBS_DROPDOWN and CBS_DROPDOWNLIST styles). If it were a child of the ComboBox control, dropping down the list box would clip it to the parent, and it wouldn't display.
A combo box receives WM_CTLCOLORMSGBOX..WM_CTLCOLORSTATIC messages for its component controls when they need to be painted. This allows the combo box to specify a color for these controls. The HIWORD of the lParam in this message is the type of the control. In case of the combo box, Windows sends it a WM_CTLCOLORLISTBOX message with the lParam contains the handle of the list box control.
Once you obtain the handle to the list box control window, you can resize the control by using the MoveWindow API.
The following code sample demonstrates how to do this. This sample demonstrates deriving new component from standard combo box and changing its behavior.
unit siComboBox;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TsiComboBox = class(TComboBox)
private
{ Private declarations }
FFirst: boolean;
FRect: TRect;
FListHandle: HWND;
FCWX: integer;
FCX: integer;
FCY: integer;
protected
{ Protected declarations }
// We should override this for changing behavior
procedure WndProc(var Message: TMessage); override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
published
{ Published declarations }
// Properties correspond the width, top and left positions of drop down list:
property CWX: integer read FCWX write FCWX default 0;
property CX: integer read FCX write FCX default 0;
property CY: integer read FCY write FCY default 0;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('siComponents', [TsiComboBox]);
end;
{ TsiComboBox }
constructor TsiComboBox.Create(AOwner: TComponent);
begin
inherited;
FFirst := True;
FCX := 0;
FCWX := 0;
FCY := 0;
end;
procedure TsiComboBox.WndProc(var Message: TMessage);
//Start modifications added by Bjarne Winkler
Var
CurRect: TRect;
//End modifications added by Bjarne Winkler
begin
inherited;
if Message.Msg = WM_CTLCOLORLISTBOX then begin
// Getting handle of list box
FListHandle := Message.LParam;
// Getting rectangle of list box
//Start modifications added by Bjarne Winkler
GetWindowRect ( FListHandle, CurRect );
If (CurRect.Left FRect.Left) Or (CurRect.Top FRect.Top) Then
Begin
FRect := CurRect;
End;
//End modifications added by Bjarne Winkler
// Resizing list box rectangle
MoveWindow ( FListHandle, FRect.left + FCX, FRect.top + FCY,
(FRect.right - FRect.left + FCWX),
FRect.bottom - FRect.top, TRUE );
end;
end;
end.