📄 dialogs.pas
字号:
procedure ShowMessage(const Msg: string);
procedure ShowMessageFmt(const Msg: string; Params: array of const);
procedure ShowMessagePos(const Msg: string; X, Y: Integer);
{ Input dialog }
function InputBox(const ACaption, APrompt, ADefault: string): string;
function InputQuery(const ACaption, APrompt: string;
var Value: string): Boolean;
function PromptForFileName(var AFileName: string; const AFilter: string = '';
const ADefaultExt: string = ''; const ATitle: string = '';
const AInitialDir: string = ''; SaveDialog: Boolean = False): Boolean;
{ Win98 and Win2k will default to the "My Documents" folder if the InitialDir
property is empty and no files of the filtered type are contained in the
current directory. Set this flag to True to force TOpenDialog and descendents
to always open in the current directory when InitialDir is empty. (Same
behavior as setting InitialDir to '.') }
var
ForceCurrentDirectory: Boolean = False;
implementation
uses
ExtCtrls, Consts, Dlgs, Math;
{ Private globals }
var
CreationControl: TCommonDialog = nil;
HelpMsg: Cardinal;
FindMsg: Cardinal;
WndProcPtrAtom: TAtom = 0;
{ Center the given window on the screen }
procedure CenterWindow(Wnd: HWnd);
var
Rect: TRect;
Monitor: TMonitor;
begin
GetWindowRect(Wnd, Rect);
if Application.MainForm <> nil then
begin
if Assigned(Screen.ActiveForm) then
Monitor := Screen.ActiveForm.Monitor
else
Monitor := Application.MainForm.Monitor;
end
else
Monitor := Screen.Monitors[0];
SetWindowPos(Wnd, 0,
Monitor.Left + ((Monitor.Width - Rect.Right + Rect.Left) div 2),
Monitor.Top + ((Monitor.Height - Rect.Bottom + Rect.Top) div 3),
0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
end;
{ Generic dialog hook. Centers the dialog on the screen in response to
the WM_INITDIALOG message }
function DialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
begin
Result := 0;
if Msg = WM_INITDIALOG then
begin
CenterWindow(Wnd);
CreationControl.FHandle := Wnd;
CreationControl.FDefWndProc := Pointer(SetWindowLong(Wnd, GWL_WNDPROC,
Longint(CreationControl.FObjectInstance)));
CallWindowProc(CreationControl.FObjectInstance, Wnd, Msg, WParam, LParam);
CreationControl := nil;
end;
end;
{ TCommonDialog }
constructor TCommonDialog.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCtl3D := True;
{$IFDEF MSWINDOWS}
FObjectInstance := Classes.MakeObjectInstance(MainWndProc);
{$ENDIF}
{$IFDEF LINUX}
FObjectInstance := WinUtils.MakeObjectInstance(MainWndProc);
{$ENDIF}
end;
destructor TCommonDialog.Destroy;
begin
{$IFDEF MSWINDOWS}
if FObjectInstance <> nil then Classes.FreeObjectInstance(FObjectInstance);
{$ENDIF}
{$IFDEF LINUX}
if FObjectInstance <> nil then WinUtils.FreeObjectInstance(FObjectInstance);
{$ENDIF}
inherited Destroy;
end;
function TCommonDialog.MessageHook(var Msg: TMessage): Boolean;
begin
Result := False;
if (Msg.Msg = HelpMsg) and (FHelpContext <> 0) then
begin
Application.HelpContext(FHelpContext);
Result := True;
end;
end;
procedure TCommonDialog.DefaultHandler(var Message);
begin
if FHandle <> 0 then
with TMessage(Message) do
Result := CallWindowProc(FDefWndProc, FHandle, Msg, WParam, LParam)
else inherited DefaultHandler(Message);
end;
procedure TCommonDialog.MainWndProc(var Message: TMessage);
begin
try
WndProc(Message);
except
Application.HandleException(Self);
end;
end;
procedure TCommonDialog.WndProc(var Message: TMessage);
begin
Dispatch(Message);
end;
procedure TCommonDialog.WMDestroy(var Message: TWMDestroy);
begin
inherited;
DoClose;
end;
procedure TCommonDialog.WMInitDialog(var Message: TWMInitDialog);
begin
{ Called only by non-explorer style dialogs }
DoShow;
{ Prevent any further processing }
Message.Result := 0;
end;
procedure TCommonDialog.WMNCDestroy(var Message: TWMNCDestroy);
begin
inherited;
FHandle := 0;
end;
function TCommonDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
type
TDialogFunc = function(var DialogData): Bool stdcall;
var
ActiveWindow: HWnd;
WindowList: Pointer;
FPUControlWord: Word;
FocusState: TFocusState;
begin
ActiveWindow := GetActiveWindow;
WindowList := DisableTaskWindows(0);
FocusState := SaveFocusState;
try
Application.HookMainWindow(MessageHook);
asm
// Avoid FPU control word change in NETRAP.dll, NETAPI32.dll, etc
FNSTCW FPUControlWord
end;
try
CreationControl := Self;
Result := TDialogFunc(DialogFunc)(DialogData);
finally
asm
FNCLEX
FLDCW FPUControlWord
end;
Application.UnhookMainWindow(MessageHook);
end;
finally
EnableTaskWindows(WindowList);
SetActiveWindow(ActiveWindow);
RestoreFocusState(FocusState);
end;
end;
procedure TCommonDialog.DoClose;
begin
if Assigned(FOnClose) then FOnClose(Self);
end;
procedure TCommonDialog.DoShow;
begin
if Assigned(FOnShow) then FOnShow(Self);
end;
{ Open and Save dialog routines }
function ExplorerHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
begin
Result := 0;
if Msg = WM_INITDIALOG then
begin
CreationControl.FHandle := Wnd;
CreationControl.FDefWndProc := Pointer(SetWindowLong(Wnd, GWL_WNDPROC,
Longint(CreationControl.FObjectInstance)));
CallWindowProc(CreationControl.FObjectInstance, Wnd, Msg, WParam, LParam);
CreationControl := nil;
end
else if (Msg = WM_NOTIFY) and (POFNotify(LParam)^.hdr.code = CDN_INITDONE) then
CenterWindow(GetWindowLong(Wnd, GWL_HWNDPARENT));
end;
{ TOpenDialog }
constructor TOpenDialog.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FHistoryList := TStringList.Create;
FOptions := [ofHideReadOnly, ofEnableSizing];
FOptionsEx := [];
FFiles := TStringList.Create;
FFilterIndex := 1;
FFileEditStyle := fsEdit;
end;
destructor TOpenDialog.Destroy;
begin
FFiles.Free;
FHistoryList.Free;
inherited Destroy;
end;
function TOpenDialog.CanClose(var OpenFileName: TOpenFileName): Boolean;
begin
GetFileNames(OpenFileName);
Result := DoCanClose;
FFiles.Clear;
end;
procedure TOpenDialog.WndProc(var Message: TMessage);
var
Index: Integer;
Include: Boolean;
begin
Message.Result := 0;
{ If not ofOldStyleDialog then DoShow on CDN_INITDONE, not WM_INITDIALOG }
if (Message.Msg = WM_INITDIALOG) and not (ofOldStyleDialog in Options) then Exit
else if (Message.Msg = WM_NOTIFY) then
case (POFNotify(Message.LParam)^.hdr.code) of
CDN_FILEOK:
if not CanClose(POFNotify(Message.LParam)^.lpOFN^) then
begin
Message.Result := 1;
SetWindowLong(Handle, DWL_MSGRESULT, Message.Result);
Exit;
end;
CDN_INITDONE: DoShow;
CDN_SELCHANGE: DoSelectionChange;
CDN_FOLDERCHANGE: DoFolderChange;
CDN_TYPECHANGE:
begin
Index := POFNotify(Message.LParam)^.lpOFN^.nFilterIndex;
if Index <> FCurrentFilterIndex then
begin
FCurrentFilterIndex := Index;
DoTypeChange;
end;
end;
CDN_INCLUDEITEM:
if Message.LParam <> 0 then
begin
Include := True;
DoIncludeItem(TOFNotifyEx(POFNotifyEx(Message.LParam)^), Include);
Message.Result := Byte(Include);
end;
end;
inherited WndProc(Message);
end;
function TOpenDialog.DoCanClose: Boolean;
begin
Result := True;
if Assigned(FOnCanClose) then FOnCanClose(Self, Result);
end;
procedure TOpenDialog.DoSelectionChange;
begin
if Assigned(FOnSelectionChange) then FOnSelectionChange(Self);
end;
procedure TOpenDialog.DoFolderChange;
begin
if Assigned(FOnFolderChange) then FOnFolderChange(Self);
end;
procedure TOpenDialog.DoTypeChange;
begin
if Assigned(FOnTypeChange) then FOnTypeChange(Self);
end;
procedure TOpenDialog.ReadFileEditStyle(Reader: TReader);
begin
{ Ignore FileEditStyle }
Reader.ReadIdent;
end;
procedure TOpenDialog.DefineProperties(Filer: TFiler);
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('FileEditStyle', ReadFileEditStyle, nil, False);
end;
{$IFDEF LINUX}
function DRIVE_GetRoot(Drive: Integer): PChar; cdecl; external 'libwine.borland.so' name 'DRIVE_GetRoot';
function FixFileName(const FileName: string): string;
var
Root: string;
I: Integer;
begin
if (Length(FileName) > 2) and (FileName[2] = ':') then
begin
Result := Copy(FileName, 3, MaxInt);
Root := DRIVE_GetRoot(Ord(UpCase(FileName[1])) - Ord('A'));
if IsPathDelimiter(Root, Length(Root)) then
Delete(Root, Length(Root) - 1, 1);
Result := Root + PathDelim + Result;
end else Result := FileName;
for I := 1 to Length(Result) do
if Result[I] = '\' then Result[I] := PathDelim;
end;
{$ENDIF}
function FixFileName(const FileName: string): string;
begin
Result := FileName;
end;
function TOpenDialog.DoExecute(Func: Pointer): Bool;
const
MultiSelectBufferSize = High(Word) - 16;
OpenOptions: array [TOpenOption] of DWORD = (
OFN_READONLY, OFN_OVERWRITEPROMPT, OFN_HIDEREADONLY,
OFN_NOCHANGEDIR, OFN_SHOWHELP, OFN_NOVALIDATE, OFN_ALLOWMULTISELECT,
OFN_EXTENSIONDIFFERENT, OFN_PATHMUSTEXIST, OFN_FILEMUSTEXIST,
OFN_CREATEPROMPT, OFN_SHAREAWARE, OFN_NOREADONLYRETURN,
OFN_NOTESTFILECREATE, OFN_NONETWORKBUTTON, OFN_NOLONGNAMES,
OFN_EXPLORER, OFN_NODEREFERENCELINKS, OFN_ENABLEINCLUDENOTIFY,
OFN_ENABLESIZING, OFN_DONTADDTORECENT, OFN_FORCESHOWHIDDEN);
OpenOptionsEx: array [TOpenOptionEx] of DWORD = (OFN_EX_NOPLACESBAR);
var
Option: TOpenOption;
OptionEx: TOpenOptionEx;
OpenFilename: TOpenFilename;
function AllocFilterStr(const S: string): string;
var
P: PChar;
begin
Result := '';
if S <> '' then
begin
Result := S + #0; // double null terminators
P := AnsiStrScan(PChar(Result), '|');
while P <> nil do
begin
P^ := #0;
Inc(P);
P := AnsiStrScan(P, '|');
end;
end;
end;
var
TempFilter, TempFilename, TempExt: string;
begin
FFiles.Clear;
FillChar(OpenFileName, SizeOf(OpenFileName), 0);
with OpenFilename do
begin
if (Win32MajorVersion >= 5) and (Win32Platform = VER_PLATFORM_WIN32_NT) or { Win2k }
((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and (Win32MajorVersion >= 4) and (Win32MinorVersion >= 90)) then { WinME }
lStructSize := SizeOf(TOpenFilename)
else
lStructSize := SizeOf(TOpenFilename) - (SizeOf(DWORD) shl 1) - SizeOf(Pointer); { subtract size of added fields }
hInstance := SysInit.HInstance;
TempFilter := AllocFilterStr(FFilter);
lpstrFilter := PChar(TempFilter);
nFilterIndex := FFilterIndex;
FCurrentFilterIndex := FFilterIndex;
if ofAllowMultiSelect in FOptions then
nMaxFile := MultiSelectBufferSize else
nMaxFile := MAX_PATH;
SetLength(TempFilename, nMaxFile + 2);
lpstrFile := PChar(TempFilename);
FillChar(lpstrFile^, nMaxFile + 2, 0);
StrLCopy(lpstrFile, PChar(FFileName), nMaxFile);
if (FInitialDir = '') and ForceCurrentDirectory then
lpstrInitialDir := '.'
else
lpstrInitialDir := PChar(FInitialDir);
lpstrTitle := PChar(FTitle);
Flags := OFN_ENABLEHOOK;
FlagsEx := 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -