📄 fr_combo.pas
字号:
{***************************************************}
{ }
{ Flat ComboBox, FontComboBox v1.0 }
{ For Delphi 2,3,4,5. }
{ Freeware. }
{ }
{ Copyright (c) 1999 by: }
{ Dmitry Statilko (dima_misc@hotbox.ru) }
{ - Main idea and realisation of Flat ComboBox }
{ inherited from TCustomComboBox }
{ }
{ Vladislav Necheporenko (andy@ukr.net) }
{ - Help in bug fixes }
{ - Adaptation to work on Delphi 2 }
{ - MRU list in FontComboBox that stored values }
{ in regitry }
{ - Font preview box in FontComboBox }
{ }
{***************************************************}
unit FR_Combo;
interface
{$I FR.inc}
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, CommCtrl, ExtCtrls, Registry;
type
TfrCustomComboBox = class(TCustomComboBox)
private
FUpDropdown: Boolean;
FButtonWidth: Integer;
msMouseInControl: Boolean;
FListHandle: HWND;
FListInstance: Pointer;
FDefListProc: Pointer;
FChildHandle: HWND;
FSolidBorder: Boolean;
FReadOnly: Boolean;
FEditOffset: Integer;
procedure ListWndProc(var Message: TMessage);
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
procedure CMEnabledChanged(var Msg: TMessage); message CM_ENABLEDCHANGED;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure PaintButtonGlyph(DC: HDC; x: Integer; y: Integer);
procedure PaintButton(bnStyle: Integer);
procedure PaintBorder(DC: HDC; const SolidBorder: Boolean);
procedure PaintDisabled;
function GetSolidBorder: Boolean;
function GetListHeight: Integer;
procedure SetReadOnly(Value: Boolean);
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure ComboWndProc(var Message: TMessage; ComboWnd: HWnd; ComboProc: Pointer); override;
procedure WndProc(var Message: TMessage); override;
procedure CreateWnd; override;
property SolidBorder: Boolean read FSolidBorder;
property ReadOnly: Boolean read FReadOnly write SetReadOnly default False;
procedure DrawImage(DC: HDC; Index: Integer; R: TRect); dynamic;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
{ TfrComboBox }
TfrComboBox = class(TfrCustomComboBox)
published
property Color;
property DragMode;
property DragCursor;
property DropDownCount;
property Enabled;
property Font;
property ItemHeight;
property Items;
property MaxLength;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Sorted;
property TabOrder;
property TabStop;
property Text;
property ReadOnly;
property Visible;
property ItemIndex;
property OnChange;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDrawItem;
property OnDropDown;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnStartDrag;
{$IFDEF Delphi4}
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
property OnEndDock;
property OnStartDock;
{$ENDIF}
end;
TfrFontPreview = class(TWinControl)
private
FPanel: TPanel;
protected
procedure CreateParams(var Params: TCreateParams); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
{ TFontComboBox }
TfrFontComboBox = class(TfrCustomComboBox)
private
frFontViewForm: TfrFontPreview;
FRegKey: String;
FTrueTypeBMP: TBitmap;
FOnClick: TNotifyEvent;
FUpdate: Boolean;
FShowMRU: Boolean;
Numused: Integer;
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMFontChange(var Message: TMessage); message CM_FONTCHANGE;
procedure SetRegKey(Value: String);
protected
procedure Loaded; override;
procedure Init;
procedure Reset;
procedure PopulateList; virtual;
procedure Click; override;
procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
procedure DrawImage(DC: HDC; Index: Integer; R: TRect); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property ShowMRU: Boolean read FShowMRU write FShowMRU default True;
property MRURegKey: String read FRegKey write SetRegKey;
property Text;
property Color;
property DragMode;
property DragCursor;
property DropDownCount;
property Enabled;
property Font;
{$IFDEF Delphi4}
property Anchors;
property BiDiMode;
property Constraints;
property DragKind;
property ParentBiDiMode;
{$ENDIF}
property ItemHeight;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnChange;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDropDown;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnStartDrag;
{$IFDEF Delphi4}
property OnEndDock;
property OnStartDock;
{$ENDIF}
end;
implementation
{$R *.RES}
{$IFDEF Delphi6}
{$WARN SYMBOL_DEPRECATED OFF}
{$ENDIF}
uses Printers;
//--- Additional functions -----------------------------------------------------
function Min(val1, val2: Word): Word;
begin
Result := val1;
if val1 > val2 then
Result := val2;
end;
function GetFontMetrics(Font: TFont): TTextMetric;
var
DC: HDC;
SaveFont: HFont;
begin
DC := GetDC(0);
SaveFont := SelectObject(DC, Font.Handle);
GetTextMetrics(DC, Result);
SelectObject(DC, SaveFont);
ReleaseDC(0, DC);
end;
function GetFontHeight(Font: TFont): Integer;
begin
Result := GetFontMetrics(Font).tmHeight;
end;
//--- TfrCustomComboBox ---------------------------------------------------------
constructor TfrCustomComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle + [csReplicatable];
FListInstance := MakeObjectInstance(ListWndProc);
FDefListProc := nil;
FButtonWidth := 11;
ItemHeight := GetFontHeight(Font);
Width := 100;
FEditOffset := 0;
end;
destructor TfrCustomComboBox.Destroy;
begin
inherited Destroy;
FreeObjectInstance(FListInstance);
end;
procedure TfrCustomComboBox.SetReadOnly(Value: Boolean);
begin
if FReadOnly <> Value then
begin
FReadOnly := Value;
if HandleAllocated then
SendMessage(EditHandle, EM_SETREADONLY, Ord(Value), 0);
end;
end;
procedure TfrCustomComboBox.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
Style := (Style and not CBS_DROPDOWNLIST) or CBS_OWNERDRAWFIXED or CBS_DROPDOWN;
end;
procedure TfrCustomComboBox.CreateWnd;
var
exStyle: Integer;
begin
inherited;
SendMessage(EditHandle, EM_SETREADONLY, Ord(FReadOnly), 0);
// Desiding, which of the handles is DropDown list handle...
if FChildHandle <> EditHandle then
FListHandle := FChildHandle;
//.. and superclassing it
FDefListProc := Pointer(GetWindowLong(FListHandle, GWL_WNDPROC));
SetWindowLong(FListHandle, GWL_WNDPROC, Longint(FListInstance));
// here we setting up the border's edge
exStyle := GetWindowLong(FListHandle, GWL_EXSTYLE);
SetWindowLong(FListHandle, GWL_EXSTYLE, exStyle or WS_EX_CLIENTEDGE);
exStyle := GetWindowLong(FListHandle, GWL_STYLE);
SetWindowLong(FListHandle, GWL_STYLE, exStyle and not WS_BORDER );
end;
procedure TfrCustomComboBox.ListWndProc(var Message: TMessage);
var
p: TPoint;
procedure CallDefaultProc;
begin
with Message do
Result := CallWindowProc(FDefListProc, FListHandle, Msg, WParam, LParam);
end;
procedure PaintListFrame;
var
DC: HDC;
R: TRect;
begin
GetWindowRect(FListHandle, R);
OffsetRect (R, -R.Left, -R.Top);
DC := GetWindowDC(FListHandle);
DrawEdge(DC, R, EDGE_RAISED, BF_RECT);
ReleaseDC(FListHandle, DC);
end;
begin
case Message.Msg of
WM_NCPAINT:
begin
CallDefaultProc;
PaintListFrame;
end;
LB_SETTOPINDEX:
begin
if ItemIndex > DropDownCount then
CallDefaultProc;
end;
WM_WINDOWPOSCHANGING:
with TWMWindowPosMsg(Message).WindowPos^ do
begin
// calculating the size of the drop down list
cx := Width - 1;
cy := GetListHeight;
p.x := cx;
p.y := cy + GetFontHeight(Font) + 6;
p := ClientToScreen(p);
FUpDropdown := False;
if p.y > Screen.Height then //if DropDownList showing below
begin
y := y - 2;
FUpDropdown := True;
end;
end;
else
CallDefaultProc;
end;
end;
procedure TfrCustomComboBox.WndProc(var Message: TMessage);
begin
case Message.Msg of
WM_SETTEXT:
Invalidate;
WM_PARENTNOTIFY:
if LoWord(Message.wParam)=WM_CREATE then begin
if FDefListProc <> nil then
begin
// This check is necessary to be sure that combo is created, not
// RECREATED (somehow CM_RECREATEWND does not work)
SetWindowLong(FListHandle, GWL_WNDPROC, Longint(FDefListProc));
FDefListProc := nil;
FChildHandle := Message.lParam;
end
else
begin
// WM_Create is the only event I found where I can get the ListBox handle.
// The fact that combo box usually creates more then 1 handle complicates the
// things, so I have to have the FChildHandle to resolve it later (in CreateWnd).
if FChildHandle = 0 then
FChildHandle := Message.lParam
else
FListHandle := Message.lParam;
end;
end;
WM_WINDOWPOSCHANGING:
MoveWindow(EditHandle, 3+FEditOffset, 3, Width-FButtonWidth-7-FEditOffset,
Height-6, True);
end;
inherited;
end;
procedure TfrCustomComboBox.WMPaint(var Message: TWMPaint);
var
PS, PSE: TPaintStruct;
begin
BeginPaint(Handle,PS);
try
if Enabled then
begin
DrawImage(PS.HDC, ItemIndex ,Rect(3, 3, FEditOffset + 3, Height - 3));
if GetSolidBorder then
begin
PaintBorder(PS.HDC, True);
if DroppedDown then
PaintButton(2)
else
PaintButton(1);
end else
begin
PaintBorder(PS.HDC, False);
PaintButton(0);
end;
end else
begin
BeginPaint(EditHandle, PSE);
try
PaintDisabled;
finally
EndPaint(EditHandle, PSE);
end;
end;
finally
EndPaint(Handle,PS);
end;
Message.Result := 0;
end;
procedure TfrCustomComboBox.DrawImage(DC: HDC; Index: Integer; R: TRect);
begin
if FEditOffset > 0 then
FillRect(DC, R, GetSysColorBrush(COLOR_WINDOW));
end;
procedure TfrCustomComboBox.ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
ComboProc: Pointer);
var
DC: HDC;
begin
inherited;
if (ComboWnd = EditHandle) then
case Message.Msg of
WM_SETFOCUS:
begin
DC:=GetWindowDC(Handle);
PaintBorder(DC,True);
PaintButton(1);
ReleaseDC(Handle,DC);
end;
WM_KILLFOCUS:
begin
DC:=GetWindowDC(Handle);
PaintBorder(DC,False);
PaintButton(0);
ReleaseDC(Handle,DC);
end;
end;
end;
procedure TfrCustomComboBox.CNCommand(var Message: TWMCommand);
begin
inherited;
if (Message.NotifyCode in [CBN_CLOSEUP]) then
PaintButton(1);
end;
procedure TfrCustomComboBox.PaintBorder(DC: HDC; const SolidBorder: Boolean);
var
R: TRect;
BtnFaceBrush, WindowBrush: HBRUSH;
begin
BtnFaceBrush := GetSysColorBrush(COLOR_BTNFACE);
WindowBrush := GetSysColorBrush(COLOR_WINDOW);
GetWindowRect(Handle, R);
OffsetRect (R, -R.Left, -R.Top);
InflateRect(R,-1,-1);
FrameRect (DC, R, BtnFaceBrush);
InflateRect(R,-1,-1);
R.Right:=R.Right - FButtonWidth - 1;
FrameRect (DC, R, WindowBrush);
if SolidBorder then
begin
GetWindowRect(Handle, R);
OffsetRect (R, -R.Left, -R.Top);
DrawEdge (DC, R, BDR_SUNKENOUTER, BF_RECT);
end else
begin
GetWindowRect(Handle, R);
OffsetRect (R, -R.Left, -R.Top);
FrameRect (DC, R, BtnFaceBrush);
end;
end;
procedure TfrCustomComboBox.PaintButtonGlyph(DC: HDC; x: Integer; y: Integer);
var
Pen, SavePen: HPEN;
begin
Pen := CreatePen(PS_SOLID, 1, ColorToRGB(clBlack));
SavePen := SelectObject(DC, Pen);
MoveToEx(DC, x, y, nil);
LineTo(DC, x + 5, y);
MoveToEx(DC, x + 1, y + 1, nil);
LineTo(DC, x + 4, y + 1);
MoveToEx(DC, x + 2, y + 2, nil);
LineTo(DC, x + 3, y + 2);
SelectObject(DC, SavePen);
DeleteObject(Pen);
end;
procedure TfrCustomComboBox.PaintButton(bnStyle: Integer);
var
R: TRect;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -