unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
ComboBox1: TComboBox;
ComboBox2: TComboBox;
ComboBox3: TComboBox;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
cwpHandle: THandle;
SaveRight:Integer;
implementation
{$R *.dfm}
procedure AutoSetComboxDropDownWidth( AComboBox: TComboBox );
var
i: Integer;
MaxWidth: Integer;
CurWidth: Integer;
TempSize: SIZE;
TempHDC: HDC;
SaveFont: HFont;
begin
MaxWidth := AComboBox.Width; //(GetSystemMetrics(SM_CXVSCROLL)*2);
TempHDC := GetDC(0);
try
for i := 0 to AComboBox.Items.Count-1 do
begin
SaveFont := SelectObject( TempHDC, AComboBox.Font.Handle );
Windows.GetTextExtentPoint32( TempHDC, PChar(AComboBox.Items[i]),
Length(AComboBox.Items[i]),
TempSize );
SelectObject( TempHDC, SaveFont );
//if scrollbar needed.
if AComboBox.Items.Count>AComboBox.DropDownCount then
//The 8 seems to provide a centering effect between left and right.
CurWidth := TempSize.cx + (GetSystemMetrics(SM_CXVSCROLL)+8)
else
CurWidth := TempSize.cx+8;
if CurWidth>MaxWidth then
MaxWidth := CurWidth;
end;
finally
ReleaseDC(0, TempHDC );
end;
SaveRight := AComboBox.ClientOrigin.X + AComboBox.Width;
AComboBox.Perform( CB_SETDROPPEDWIDTH, MaxWidth, 0 );
end;
procedure MoveDropDownListIfNecessary( AComboBoxListHandle: LongInt );
var
R: TRect;
begin
GetWindowRect( AComboBoxListHandle, R );
if R.Right>=Screen.Width then
begin
MoveWindow( AComboBoxListHandle, SaveRight-(R.Right-R.Left)-1, R.Top,
R.Right-R.Left, R.Bottom-R.Top, True );
end;
end;
function HookCallbackFunction(nCode: Integer; wParam: LongInt;
lParam: LongInt): Integer; stdcall;
var
wNotifyCode: Integer;
Control: TWinControl;
ListHandle: LongInt;
begin
Result := CallNextHookEx(cwpHandle,nCode,wParam,lParam);
// Don't do anything when program is closing
if (Application.Terminated) or (nCode<0) then
Exit;
if nCode=HC_ACTION then
begin
if PCWPStruct(LParam)^.message = WM_COMMAND then
begin
wNotifyCode := HIWORD(PCWPStruct(LParam)^.wParam);
if wNotifyCode = CBN_DROPDOWN then
begin
Control := FindControl( PCWPStruct(LParam)^.lParam );
if (Control<>nil) and (Control is TComboBox) then
AutoSetComboxDropDownWidth( TComboBox( Control ) );
end;
end
else if PCWPStruct(LParam)^.message = WM_CTLCOLORLISTBOX then
begin
ListHandle := PCWPStruct(LParam)^.lParam;
MoveDropDownListIfNecessary( ListHandle );
end;
end;
end;
initialization
cwpHandle := SetWindowsHookEx( WH_CALLWNDPROC, @HookCallbackFunction, 0, MainThreadID );
finalization
if cwpHandle <> 0 then
UnhookWindowsHookEx( cwpHandle );
end.