📄 dialogs.pas
字号:
SetWindowPos(Wnd, 0, Left, Top, 0, 0, SWP_NOACTIVATE or
SWP_NOSIZE or SWP_NOZORDER);
SetProp(Wnd, MakeIntAtom(WndProcPtrAtom), GetWindowLong(Wnd, GWL_WNDPROC));
SetWindowLong(Wnd, GWL_WNDPROC, Longint(@FindReplaceWndProc));
Result := 1;
end;
end;
const
FindOptions: array[TFindOption] of DWORD = (
FR_DOWN, FR_FINDNEXT, FR_HIDEMATCHCASE, FR_HIDEWHOLEWORD,
FR_HIDEUPDOWN, FR_MATCHCASE, FR_NOMATCHCASE, FR_NOUPDOWN, FR_NOWHOLEWORD,
FR_REPLACE, FR_REPLACEALL, FR_WHOLEWORD, FR_SHOWHELP);
{ TFindDialog }
constructor TFindDialog.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FOptions := [frDown];
FPosition.X := -1;
FPosition.Y := -1;
with FFindReplace do
begin
lStructSize := SizeOf(TFindReplace);
hWndOwner := Application.Handle;
hInstance := SysInit.HInstance;
lpstrFindWhat := FFindText;
wFindWhatLen := SizeOf(FFindText);
lpstrReplaceWith := FReplaceText;
wReplaceWithLen := SizeOf(FReplaceText);
lCustData := Longint(Self);
lpfnHook := FindReplaceDialogHook;
end;
FFindReplaceFunc := @CommDlg.FindText;
end;
destructor TFindDialog.Destroy;
begin
if FFindHandle <> 0 then SendMessage(FFindHandle, WM_CLOSE, 0, 0);
if Assigned(FRedirector) then
TRedirectorWindow(FRedirector).FFindReplaceDialog := nil;
FreeAndNil(FRedirector);
inherited Destroy;
end;
procedure TFindDialog.CloseDialog;
begin
if FFindHandle <> 0 then PostMessage(FFindHandle, WM_CLOSE, 0, 0);
end;
function GetTopWindow(Wnd: THandle; var ReturnVar: THandle):Bool; stdcall;
var
Test: TWinControl;
begin
Test := FindControl(Wnd);
Result := True;
if Assigned(Test) and (Test is TForm) then
begin
ReturnVar := Wnd;
Result := False;
end;
end;
function TFindDialog.Execute: Boolean;
var
Option: TFindOption;
begin
if FFindHandle <> 0 then
begin
BringWindowToTop(FFindHandle);
Result := True;
end else
begin
FFindReplace.Flags := FR_ENABLEHOOK;
FFindReplace.lpfnHook := FindReplaceDialogHook;
FRedirector := TRedirectorWindow.Create(nil);
with TRedirectorWindow(FRedirector) do
begin
FFindReplaceDialog := Self;
EnumThreadWindows(GetCurrentThreadID, @GetTopWindow, LPARAM(@FFormHandle));
end;
FFindReplace.hWndOwner := FRedirector.Handle;
for Option := Low(Option) to High(Option) do
if Option in FOptions then
FFindReplace.Flags := FFindReplace.Flags or FindOptions[Option];
if Template <> nil then
begin
FFindReplace.Flags := FFindReplace.Flags or FR_ENABLETEMPLATE;
FFindReplace.lpTemplateName := Template;
end;
CreationControl := Self;
FFindHandle := FFindReplaceFunc(FFindReplace);
Result := FFindHandle <> 0;
end;
end;
procedure TFindDialog.Find;
begin
if Assigned(FOnFind) then FOnFind(Self);
end;
function TFindDialog.GetFindText: string;
begin
Result := FFindText;
end;
function TFindDialog.GetLeft: Integer;
begin
Result := Position.X;
end;
function TFindDialog.GetPosition: TPoint;
var
Rect: TRect;
begin
Result := FPosition;
if FFindHandle <> 0 then
begin
GetWindowRect(FFindHandle, Rect);
Result := Rect.TopLeft;
end;
end;
function TFindDialog.GetReplaceText: string;
begin
Result := FReplaceText;
end;
function TFindDialog.GetTop: Integer;
begin
Result := Position.Y;
end;
function TFindDialog.MessageHook(var Msg: TMessage): Boolean;
var
Option: TFindOption;
Rect: TRect;
begin
Result := inherited MessageHook(Msg);
if not Result then
if (Msg.Msg = FindMsg) and (Pointer(Msg.LParam) = @FFindReplace) then
begin
FOptions := [];
for Option := Low(Option) to High(Option) do
if (FFindReplace.Flags and FindOptions[Option]) <> 0 then
Include(FOptions, Option);
if (FFindReplace.Flags and FR_FINDNEXT) <> 0 then
Find
else
if (FFindReplace.Flags and (FR_REPLACE or FR_REPLACEALL)) <> 0 then
Replace
else
if (FFindReplace.Flags and FR_DIALOGTERM) <> 0 then
begin
GetWindowRect(FFindHandle, Rect);
FPosition := Rect.TopLeft;
FFindHandle := 0;
PostMessage(FRedirector.Handle,CM_RELEASE,0,0); // free redirector later
FRedirector := nil;
end;
Result := True;
end;
end;
procedure TFindDialog.Replace;
begin
if Assigned(FOnReplace) then FOnReplace(Self);
end;
procedure TFindDialog.SetFindText(const Value: string);
begin
StrLCopy(FFindText, PChar(Value), SizeOf(FFindText) - 1);
end;
procedure TFindDialog.SetLeft(Value: Integer);
begin
SetPosition(Point(Value, Top));
end;
procedure TFindDialog.SetPosition(const Value: TPoint);
begin
if (FPosition.X <> Value.X) or (FPosition.Y <> Value.Y) then
begin
FPosition := Value;
if FFindHandle <> 0 then
SetWindowPos(FFindHandle, 0, Value.X, Value.Y, 0, 0,
SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
end;
end;
procedure TFindDialog.SetReplaceText(const Value: string);
begin
StrLCopy(FReplaceText, PChar(Value), SizeOf(FReplaceText) - 1);
end;
procedure TFindDialog.SetTop(Value: Integer);
begin
SetPosition(Point(Left, Value));
end;
{ TReplaceDialog }
constructor TReplaceDialog.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FFindReplaceFunc := CommDlg.ReplaceText;
end;
{ Message dialog }
function GetAveCharSize(Canvas: TCanvas): TPoint;
var
I: Integer;
Buffer: array[0..51] of Char;
begin
for I := 0 to 25 do Buffer[I] := Chr(I + Ord('A'));
for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a'));
GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
Result.X := Result.X div 52;
end;
type
TMessageForm = class(TForm)
private
Message: TLabel;
procedure HelpButtonClick(Sender: TObject);
protected
procedure CustomKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure WriteToClipBoard(Text: String);
function GetFormText: String;
public
constructor CreateNew(AOwner: TComponent); reintroduce;
end;
constructor TMessageForm.CreateNew(AOwner: TComponent);
var
NonClientMetrics: TNonClientMetrics;
begin
inherited CreateNew(AOwner);
NonClientMetrics.cbSize := sizeof(NonClientMetrics);
if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
Font.Handle := CreateFontIndirect(NonClientMetrics.lfMessageFont);
end;
procedure TMessageForm.HelpButtonClick(Sender: TObject);
begin
Application.HelpContext(HelpContext);
end;
procedure TMessageForm.CustomKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if (Shift = [ssCtrl]) and (Key = Word('C')) then
begin
Beep;
WriteToClipBoard(GetFormText);
end;
end;
procedure TMessageForm.WriteToClipBoard(Text: String);
var
Data: THandle;
DataPtr: Pointer;
begin
if OpenClipBoard(0) then
begin
try
Data := GlobalAlloc(GMEM_MOVEABLE+GMEM_DDESHARE, Length(Text) + 1);
try
DataPtr := GlobalLock(Data);
try
Move(PChar(Text)^, DataPtr^, Length(Text) + 1);
EmptyClipBoard;
SetClipboardData(CF_TEXT, Data);
finally
GlobalUnlock(Data);
end;
except
GlobalFree(Data);
raise;
end;
finally
CloseClipBoard;
end;
end
else
raise Exception.CreateRes(@SCannotOpenClipboard);
end;
function TMessageForm.GetFormText: String;
var
DividerLine, ButtonCaptions: string;
I: integer;
begin
DividerLine := StringOfChar('-', 27) + sLineBreak;
for I := 0 to ComponentCount - 1 do
if Components[I] is TButton then
ButtonCaptions := ButtonCaptions + TButton(Components[I]).Caption +
StringOfChar(' ', 3);
ButtonCaptions := StringReplace(ButtonCaptions,'&','', [rfReplaceAll]);
Result := Format('%s%s%s%s%s%s%s%s%s%s', [DividerLine, Caption, sLineBreak,
DividerLine, Message.Caption, sLineBreak, DividerLine, ButtonCaptions,
sLineBreak, DividerLine]);
end;
var
Captions: array[TMsgDlgType] of Pointer = (@SMsgDlgWarning, @SMsgDlgError,
@SMsgDlgInformation, @SMsgDlgConfirm, nil);
IconIDs: array[TMsgDlgType] of PChar = (IDI_EXCLAMATION, IDI_HAND,
IDI_ASTERISK, IDI_QUESTION, nil);
ButtonNames: array[TMsgDlgBtn] of string = (
'Yes', 'No', 'OK', 'Cancel', 'Abort', 'Retry', 'Ignore', 'All', 'NoToAll',
'YesToAll', 'Help');
ButtonCaptions: array[TMsgDlgBtn] of Pointer = (
@SMsgDlgYes, @SMsgDlgNo, @SMsgDlgOK, @SMsgDlgCancel, @SMsgDlgAbort,
@SMsgDlgRetry, @SMsgDlgIgnore, @SMsgDlgAll, @SMsgDlgNoToAll, @SMsgDlgYesToAll,
@SMsgDlgHelp);
ModalResults: array[TMsgDlgBtn] of Integer = (
mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
mrYesToAll, 0);
var
ButtonWidths : array[TMsgDlgBtn] of integer; // initialized to zero
function CreateMessageDialog(const Msg: string; DlgType: TMsgDlgType;
Buttons: TMsgDlgButtons): TForm;
const
mcHorzMargin = 8;
mcVertMargin = 8;
mcHorzSpacing = 10;
mcVertSpacing = 10;
mcButtonWidth = 50;
mcButtonHeight = 14;
mcButtonSpacing = 4;
var
DialogUnits: TPoint;
HorzMargin, VertMargin, HorzSpacing, VertSpacing, ButtonWidth,
ButtonHeight, ButtonSpacing, ButtonCount, ButtonGroupWidth,
IconTextWidth, IconTextHeight, X, ALeft: Integer;
B, DefaultButton, CancelButton: TMsgDlgBtn;
IconID: PChar;
TextRect: TRect;
begin
Result := TMessageForm.CreateNew(Application);
with Result do
begin
BiDiMode := Application.BiDiMode;
BorderStyle := bsDialog;
Canvas.Font := Font;
KeyPreview := True;
OnKeyDown := TMessageForm(Result).CustomKeyDown;
DialogUnits := GetAveCharSize(Canvas);
HorzMargin := MulDiv(mcHorzMargin, DialogUnits.X, 4);
VertMargin := MulDiv(mcVertMargin, DialogUnits.Y, 8);
HorzSpacing := MulDiv(mcHorzSpacing, DialogUnits.X, 4);
VertSpacing := MulDiv(mcVertSpacing, DialogUnits.Y, 8);
ButtonWidth := MulDiv(mcButtonWidth, DialogUnits.X, 4);
for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
begin
if B in Buttons then
begin
if ButtonWidths[B] = 0 then
begin
TextRect := Rect(0,0,0,0);
Windows.DrawText( canvas.handle,
PChar(LoadResString(ButtonCaptions[B])), -1,
TextRect, DT_CALCRECT or DT_LEFT or DT_SINGLELINE or
DrawTextBiDiModeFlagsReadingOnly);
with TextRect do ButtonWidths[B] := Right - Left + 8;
end;
if ButtonWidths[B] > ButtonWidth then
ButtonWidth := ButtonWidths[B];
end;
end;
ButtonHeight := MulDiv(mcButtonHeight, DialogUnits.Y, 8);
ButtonSpacing := MulDiv(mcButtonSpacing, DialogUnits.X, 4);
SetRect(TextRect, 0, 0, Screen.Width div 2, 0);
DrawText(Canvas.Handle, PChar(Msg), Length(Msg)+1, TextRect,
DT_EXPANDTABS or DT_CALCRECT or DT_WORDBREAK or
DrawTextBiDiModeFlagsReadingOnly);
IconID := IconIDs[DlgType];
IconTextWidth := TextRect.Right;
IconTextHeight := TextRect.Bottom;
if IconID <> nil then
begin
Inc(IconTextWidth, 32 + HorzSpacing);
if IconTextHeight < 32 then IconTextHeight := 32;
end;
ButtonCount := 0;
for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
if B in Buttons then Inc(ButtonCount);
ButtonGroupWidth := 0;
if ButtonCount <> 0 then
ButtonGroupWidth := ButtonWidth * ButtonCount +
ButtonSpacing * (ButtonCount - 1);
ClientWidth := Max(IconTextWidth, ButtonGroupWidth) + HorzMargin * 2;
ClientHeight := IconTextHeight + ButtonHeight + VertSpacing +
VertMargin * 2;
Left := (Screen.Width div 2) - (Width div 2);
Top := (Screen.Height div 2) - (Height div 2);
if DlgType <> mtCustom then
Caption := LoadResString(Captions[DlgType]) else
Caption := Application.Title;
if IconID <> nil then
with TImage.Create(Result) do
begin
Name := 'Image';
Parent := Result;
Picture.Icon.Handle := LoadIcon(0, IconID);
SetBounds(Ho
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -