2Pascal-新时代的Pascal

 找回密码
 立即注册
搜索
热搜: fastreport
查看: 2676|回复: 12
打印 上一主题 下一主题

可以中文化的自定义对话框单元。MessageDlgCN

[复制链接]

90

主题

293

帖子

8万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
81880
跳转到指定楼层
楼主
发表于 2018-1-16 01:44:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
京东购书支持本站
首先,代码原本是 DELPHI7  的,而且不是我写的。
原作者大概是我公司的一个高管,要么就是网络上的高手。

我修改的是 XE2 版本,自然支持 Unicode ,支持 TaskDialog。

整个单元都给大家,请不要使用复制代码按钮

[mw_shl_code=delphi,true]///    <summary>
///      中文版对话框单元。
///    </summary>
unit MessageDlgCN;

{ -------------------------------------------------------------------------------
  单元: MessageDlgCN.pas
  说明: 提供了Message Dialog 函数
  ****************************************************************************
  注意:所有的按钮 index 都是从 1 开始的。默认返回 2。
  ****************************************************************************
  修改:爱吃猪头肉
  ------------------------------------------------------------------------------- }

interface

uses
  System.SysUtils, Winapi.Windows, Messages, Classes, Consts, Dialogs, Forms,
  System.Generics.Collections,
  Winapi.MultiMon, System.HelpIntfs, Vcl.Themes,
  Winapi.CommCtrl,
  Controls, Graphics, StdCtrls, ExtCtrls, ShellApi;

// type
// TMsgDlgTypeEx = (mtWarning, mtError, mtInformation, mtConfirmation, mtStop, mtCustom);

type
  TMessageDlgCNInputCloseQueryEvent = procedure (Sender: TObject; const Values: array of string; var CanClose: Boolean; QueryForm: TForm) of object;
  TMessageDlgCNInputCloseQueryFunc = reference to function (const Values: array of string; QueryForm: TForm): Boolean;

//CancelIndex 在 6.0 以上系统中没有使用。
// Create Message Dialog
function CreateMessageDialog(const Msg: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex, HelpIndex: Integer; const AOwner: TComponent = nil): TForm;
function ShowMessageDlgPosHelp(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex, HelpIndex: Integer; HelpCtx: LongInt; const HelpFileName: string;
  const X, Y: Integer; const AOwner: TComponent = nil): Integer;
function MessageDlgPos(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex: Integer; const X, Y: Integer; const AOwner: TComponent = nil): Integer;
function MessageDlgHelp(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex, HelpIndex: Integer; HelpCtx: LongInt; const HelpFileName: string;
  const AOwner: TComponent = nil): Integer;
function MessageDialog(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex: Integer; const AOwner: TComponent = nil): Integer; overload;
function MessageDialog(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const AOwner: TComponent = nil): Integer; overload;
function QuestionDialog(const Msg, MsgTitle: string; const AOwner: TComponent = nil; YesCaption: string = '';
  NoCaption: string = ''): Boolean;
function QuestionCancelDialog(const Msg, MsgTitle: string; const AOwner: TComponent = nil; YesCaption: string = '';
  NoCaption: string = ''; CancelCaption: string = ''): Integer;
procedure ShowMessagePos(const Msg, MsgTitle: string; const X, Y: Integer; const AOwner: TComponent = nil;
  OKCaption: string = '');
procedure ShowMessage(const Msg, MsgTitle: string; const AOwner: TComponent = nil; OKCaption: string = ''); overload;
procedure ShowMessage(const Msg: string; const AOwner: TComponent = nil; OKCaption: string = ''); overload;
procedure ShowWarning(const Msg, MsgTitle: string; const AOwner: TComponent = nil; OKCaption: string = ''); overload;
procedure ShowWarning(const Msg: string; const AOwner: TComponent = nil; OKCaption: string = ''); overload;
procedure ShowError(const Msg, MsgTitle: string; const AOwner: TComponent = nil; OKCaption: string = ''); overload;
procedure ShowError(const Msg: string; const AOwner: TComponent = nil; OKCaption: string = ''); overload;
procedure ShowException(E: Exception; const AOwner: TComponent = nil; OKCaption: string = ''); overload;
procedure ShowException(E: string; const AOwner: TComponent = nil; OKCaption: string = ''); overload;

function InputBox(const ACaption, APrompt, ADefault: string; const AOwner: TComponent = nil;
  CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil;
  OKCaption: string = ''; CancelCaption: string = ''): string;
function InputQuery(const ACaption, APrompt: string; var Value: string; const AOwner: TComponent = nil;
  CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean; overload;
function InputQuery(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil; const AOwner: TComponent = nil; OKCaption: string = '';
  CancelCaption: string = ''): Boolean; overload;
function InputQuery(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  CloseQueryEvent: TMessageDlgCNInputCloseQueryEvent; Context: TObject = nil; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean; overload;
function InputQueryPosHelp(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; HelpCtx: LongInt; const HelpFileName: string; CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil;
  const AOwner: TComponent = nil; OKCaption: string = ''; CancelCaption: string = ''): Boolean; overload;
function InputQueryPosHelp(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; HelpCtx: LongInt; const HelpFileName: string; CloseQueryEvent: TMessageDlgCNInputCloseQueryEvent;
  Context: TObject = nil; const AOwner: TComponent = nil; OKCaption: string = ''; CancelCaption: string = '')
  : Boolean; overload;
function InputQueryPos(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean; overload;
function InputQueryPos(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; CloseQueryEvent: TMessageDlgCNInputCloseQueryEvent; Context: TObject = nil; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean; overload;

function InputQueryEx(const ACaption, APrompt: string; var Value: string; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean;

var
  // 字体设置在 6.0 以上系统中没有使用。
  MessageDlgDefaultFontName: string = '宋体';
  MessageDlgDefaultFontSize: Integer = 9;
  MessageDlgDefaultFormFontName: string = '宋体';
  MessageDlgDefaultFormFontSize: Integer = 9;

  /// <summary>
  /// 将对话框显示在主窗体的中心,前提是没有 AOwner 。
  /// </summary>
  MessageDlgToMainFormCenter: Boolean = False;

  /// <summary>
  /// 在 4.x 5.x 系统中,对话框窗体标题使用字体。
  /// </summary>
  MessageDlgFormUseDefaultFont: Boolean = False;

  /// <summary>
  /// 对话框有 MessageBox 样式的 关闭按钮。
  /// </summary>
  MessageDlgUseMessageBoxSysCMDColse: Boolean = True;

  /// <summary>
  /// 对话框显示时发出对应类型的 Beep 。
  /// </summary>
  MessageDlgUseMessageBeep: Boolean = True;

  /// <summary>
  /// 对话框有 MessageBox 样式的 关闭按钮。
  /// </summary>
  MessageDlgInputQueryDisableSysCMDClose: Boolean = False;

//没办法代码是抄来的。虽然有改动,但还是得尊重下原作者。
//resourcestring
const
  Coderinfo = 'MsessageDlgCn By 爱吃猪头肉';
//请不要删除,请确保本代码存在,否则请不要使用,resourcestring 和 const 都可以。
//EMB 官方,如果您用了,这是可以删除的。

implementation

uses Math;

var
  TaskActiveWindow: HWnd = 0;
  TaskFirstWindow: HWnd = 0;
  TaskFirstTopMost: HWnd = 0;

function DoFindWindow(Window: HWnd; Param: LPARAM): Bool; {$IFNDEF CLR}stdcall; {$ENDIF}
begin
  if (Window <> TaskActiveWindow) and (Window <> Application.Handle) and IsWindowVisible(Window) and
    IsWindowEnabled(Window) then
    if GetWindowLong(Window, GWL_EXSTYLE) and WS_EX_TOPMOST = 0 then
    begin
      if TaskFirstWindow = 0 then
        TaskFirstWindow := Window;
    end
    else
    begin
      if TaskFirstTopMost = 0 then
        TaskFirstTopMost := Window;
    end;
  Result := True;
end;

function FindTopMostWindow(ActiveWindow: HWnd): HWnd;
var
  EnumProc: TFNWndEnumProc; // keep a reference to the delegate!
begin
  TaskActiveWindow := ActiveWindow;
  TaskFirstWindow := 0;
  TaskFirstTopMost := 0;
  EnumProc := @DoFindWindow;
  EnumThreadWindows(GetCurrentThreadID, EnumProc, 0);
  if TaskFirstWindow <> 0 then
    Result := TaskFirstWindow
  else
    Result := TaskFirstTopMost;
end;

function GetAveCharSize(Canvas: TCanvas): TPoint;
{$IF DEFINED(CLR)}
var
  I: Integer;
  Buffer: string;
  Size: TSize;
begin
  SetLength(Buffer, 52);
  for I := 0 to 25 do
    Buffer[I + 1] := Chr(I + Ord('A'));
  for I := 0 to 25 do
    Buffer[I + 27] := Chr(I + Ord('a'));
  GetTextExtentPoint(Canvas.Handle, Buffer, 52, Size);
  Result.X := Size.cx div 52;
  Result.Y := Size.cy;
end;
{$ELSE}

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;
{$IFEND}

type
  TMessageForm = class(TForm)
  private
    DlgType: TMsgDlgType;
    Message: TLabel;
    Btns: array of TButton;
    procedure HelpButtonClick(Sender: TObject);
    procedure ButtonClick(AOwner: TObject);
  protected
    procedure CustomKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure WriteToClipBoard(Text: string);
    function GetFormText: string;
    procedure DoShow; override;
    procedure DoClose(var Action: TCloseAction); override;
    procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
    procedure CreateParams(var Params: TCreateParams); override;
  public
    isCanSysCDMClose: Boolean;
    IsSysCDMClose: Boolean;
    constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); override;
  end;

constructor TMessageForm.CreateNew(AOwner: TComponent; Dummy: Integer = 0);
begin
  inherited CreateNew(AOwner, Dummy);
  Font.Assign(Screen.MessageFont);
  isCanSysCDMClose := False;
  IsSysCDMClose := True;
end;

procedure TMessageForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  // SetWindowLong(Handle,GWL_EXSTYLE,
  // GetWindowLong(Handle,GWL_EXSTYLE) or WS_EX_CONTROLPARENT);
  Params.ExStyle := Params.ExStyle or WS_EX_CONTROLPARENT;
end;

procedure TMessageForm.WMSysCommand(var Message: TWMSysCommand);
begin
  if (message.CmdType = SC_CLOSE) then
  begin
    if not isCanSysCDMClose then
    begin
      message.Result := 1;
      exit;
    end;
  end;
  inherited;
end;

procedure TMessageForm.DoShow;
var
  i: Integer;
begin
  for i := Low(Btns) to High(Btns) do
  begin
    with Btns do
    begin
      if Default then
      begin
        ActiveControl := Btns;
        break;
      end;
    end;
  end;
  if Length(Btns) <= 1 then
  begin
  end
  else if MessageDlgUseMessageBoxSysCMDColse then
  begin
    EnableMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, MF_DISABLED or MF_GRAYED or MF_BYCOMMAND);
  end;
  if MessageDlgUseMessageBeep then
    case DlgType of
      TMsgDlgType.mtWarning:
        MessageBeep(MB_ICONEXCLAMATION);
      TMsgDlgType.mtError:
        MessageBeep(MB_ICONHAND);
      TMsgDlgType.mtInformation:
        MessageBeep(MB_ICONASTERISK);
      TMsgDlgType.mtConfirmation:
        MessageBeep(MB_ICONQUESTION);
      TMsgDlgType.mtCustom:
        ;
    end;
  try
    SetFocus;
  except
  end;
  inherited;
end;

procedure TMessageForm.DoClose;
begin
  if (Application = nil) or Application.Terminated then
  begin
    ModalResult := mrCancel;
  end;
  inherited;
end;

procedure TMessageForm.HelpButtonClick(Sender: TObject);
begin
  ModalResult := mrNone;
  Application.HelpContext(HelpContext);
end;

procedure TMessageForm.ButtonClick(AOwner: TObject);
begin
  IsSysCDMClose := False;
end;

procedure TMessageForm.CustomKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if (Shift = [ssCtrl]) and (Key = Word('C')) then
  begin
    System.SysUtils.Beep;
    WriteToClipBoard(GetFormText);
  end;
end;

procedure TMessageForm.WriteToClipBoard(Text: string);
var
  Data: THandle;
{$IF DEFINED(CLR)}
  DataPtr: IntPtr;
  Buffer: TBytes;
{$ELSE}
  DataPtr: Pointer;
{$IFEND}
begin
  if OpenClipBoard(0) then
  begin
    try

{$IF DEFINED(CLR)}
      Buffer := PlatformBytesOf(Text);
      SetLength(Buffer, Length(Buffer) + Marshal.SystemDefaultCharSize);
      Data := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, Length(Buffer));
{$ELSE}
      Data := GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE, ByteLength(Text) + SizeOf(Char));
{$IFEND}
      try
        DataPtr := GlobalLock(Data);
        try
{$IF DEFINED(CLR)}
          Marshal.Copy(Buffer, 0, DataPtr, Length(Buffer));
{$ELSE}
          Move(PChar(Text)^, DataPtr^, ByteLength(Text) + SizeOf(Char));
          EmptyClipBoard;
          SetClipboardData(CF_UNICODETEXT, Data);
{$IFEND}
        finally
          GlobalUnlock(Data);
        end;
{$IF DEFINED(CLR)}
        EmptyClipBoard;
        if Marshal.SystemDefaultCharSize > 1 then
          SetClipboardData(CF_UNICODETEXT, Data)
        else
          SetClipboardData(CF_TEXT, Data)
{$IFEND}
      except
        GlobalFree(Data);
        raise;
      end;
    finally
      CloseClipBoard;
    end;
  end
  else
    raise Exception.CreateRes({$IFNDEF CLR}@{$ENDIF}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;

resourcestring
  SMsgDlgStop = 'Stop';
  SMsgDlgStop_CN = '停止';
  SMsgDlgWarning_CN = '警告';
  SMsgDlgError_CN = '错误';
  SMsgDlgInformation_CN = '信息';
  SMsgDlgConfirm_CN = '确认';

var
{$IF DEFINED(CLR)}
  Captions: array [TMsgDlgType] of string = (
    SMsgDlgWarning_CN,
    SMsgDlgError_CN,
    SMsgDlgInformation_CN,
    SMsgDlgConfirm_CN,
    // SMsgDlgStop_CN,
    ''
  );
  IconIDs: array [TMsgDlgType] of Integer = (
    IDI_EXCLAMATION,
    IDI_HAND,
    IDI_ASTERISK,
    IDI_QUESTION,
    // IDI_HAND,
    -1
  );
{$ELSE}
  Captions: array [TMsgDlgType] of Pointer = (
    @SMsgDlgWarning_CN,
    @SMsgDlgError_CN,
    @SMsgDlgInformation_CN,
    @SMsgDlgConfirm_CN,
    // @SMsgDlgStop_CN,
    nil
  );
  IconIDs: array [TMsgDlgType] of PChar = (
    IDI_EXCLAMATION,
    IDI_HAND,
    IDI_ASTERISK,
    IDI_QUESTION,
    // IDI_HAND,
    nil
  );
{$IFEND}

var
  ButtonWidths: array of Integer;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function CreateMessageDialog(const Msg: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex, HelpIndex: Integer; const AOwner: TComponent = nil): TForm;
const
  mcHorzMargin = 8;
  mcVertMargin = 8;
  mcHorzSpacing = 10;
  mcVertSpacing = 10;
  mcButtonWidth = 50;
  mcButtonHeight = 14;
  mcButtonSpacing = 4;
var
  DialogUnits: TPoint;
  i, j, HorzMargin, VertMargin, HorzSpacing, VertSpacing, ButtonWidth, ButtonHeight, ButtonSpacing, ButtonCount,
    ButtonGroupWidth, IconTextWidth, IconTextHeight, X, ALeft: Integer;
{$IF DEFINED(CLR)}
  IconID: Integer;
{$ELSE}
  IconID: PChar;
{$IFEND}
  TextRect: TRect;
begin
  if (AOwner <> nil) then
  begin
    Result := TMessageForm.CreateNew(AOwner);
  end
  else
  begin
    Result := TMessageForm.CreateNew(Application);
  end;
  TMessageForm(Result).DlgType := DlgType;
  with TMessageForm(Result) do
  begin
    isCanSysCDMClose := False;
    if CancelIndex > 0 then
    begin
      isCanSysCDMClose := True;
    end;
    if Length(Buttons) <= 1 then
    begin
      isCanSysCDMClose := True;
    end;
    if MessageDlgUseMessageBoxSysCMDColse then
    begin
      isCanSysCDMClose := False;
    end;
    Font := Screen.MessageFont;
    if MessageDlgFormUseDefaultFont then
    begin
      Font.Name := MessageDlgDefaultFormFontName;
      Font.Size := MessageDlgDefaultFormFontSize;
    end;
    Font.Charset := GetDefFontCharSet;
    BiDiMode := Application.BiDiMode;
    BorderStyle := bsDialog;
    Canvas.Font := Font;
    KeyPreview := True;
    PopupMode := pmAuto;
    Position := poDesigned;
    OnKeyDown := TMessageForm(Result).CustomKeyDown;
    // BorderIcons := [biSystemMenu];
    // FormStyle := fsStayOnTop;
    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);
    SetLength(ButtonWidths, Length(Buttons));
    j := 0;
    for i := Low(Buttons) to High(Buttons) do
    begin
      try
        if ButtonWidths[j] = 0 then
        begin
          TextRect := Rect(0, 0, 0, 0);
          Winapi.Windows.DrawText(canvas.handle, PChar(Buttons), -1, TextRect, DT_CALCRECT or DT_LEFT or
            DT_SINGLELINE or DrawTextBiDiModeFlagsReadingOnly);
          with TextRect do
            ButtonWidths := Right - Left + 8;
        end;
        if ButtonWidths > ButtonWidth then
          ButtonWidth := ButtonWidths;
      finally
        inc(j);
      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, 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 DEFINED(CLR)}
    if DlgType <> mtCustom then
{$ELSE}
    if IconID <> nil then
{$IFEND}
    begin
      Inc(IconTextWidth, 32 + HorzSpacing);
      if IconTextHeight < 32 then
        IconTextHeight := 32;
    end;
    ButtonCount := Length(Buttons);
    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
{$IF DEFINED(CLR)}
      Caption := Captions[DlgType]
    else
      Caption := Application.Title;
    if DlgType <> mtCustom then
{$ELSE}
      Caption := LoadResString(Captions[DlgType])
    else
      Caption := Application.Title;
    if IconID <> nil then
{$IFEND}
      with TImage.Create(Result) do
      begin
        Name := 'Image';
        Parent := Result;
        Picture.Icon.Handle := LoadIcon(0, IconID);
        SetBounds(HorzMargin, VertMargin, 32, 32);
      end;
    TMessageForm(Result).Message := TLabel.Create(Result);
    with TMessageForm(Result).Message do
    begin
      Name := 'Message';
      Parent := Result;
      WordWrap := True;
      Caption := Msg;
      BoundsRect := TextRect;
      BiDiMode := Result.BiDiMode;
      ALeft := IconTextWidth - TextRect.Right + HorzMargin;
      if UseRightToLeftAlignment then
        ALeft := Result.ClientWidth - ALeft - Width;
      SetBounds(ALeft, VertMargin, TextRect.Right, TextRect.Bottom);
    end;
    X := (ClientWidth - ButtonGroupWidth) div 2;
    SetLength(Btns, Length(Buttons));
    j := 0;
    for i := Low(Buttons) to High(Buttons) do
    begin
      try
        Btns := TButton.Create(Result);
        with Btns do
        begin
          Name := 'Button_' + IntToStr(j + 1);
          Parent := Result;
          Caption := Buttons;
          ModalResult := j + 1;
          if j + 1 = DefaultIndex then
          begin
            Default := True;
            ActiveControl := Btns;
          end;
          if j + 1 = CancelIndex then
            Cancel := True;
          SetBounds(X, IconTextHeight + VertMargin + VertSpacing, ButtonWidth, ButtonHeight);
          Inc(X, ButtonWidth + ButtonSpacing);
          if j + 1 = HelpIndex then
          begin
            ModalResult := mrNone;
            // HelpFile := HelpFileName;
            // HelpContext := HelpCtx;
            Tag := 0;
            OnClick := TMessageForm(Result).HelpButtonClick;
          end
          else
          begin
            OnClick := ButtonClick;
          end;
        end;
      finally
        inc(j);
      end;
    end;
  end;
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function DoMessageDlgPosHelp(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex, HelpIndex: Integer; HelpCtx: LongInt; const HelpFileName: string;
  const X, Y: Integer; const AOwner: TComponent = nil): Integer;
var
  Dialog: TMessageForm;
begin
  // Dialog := TMessageDialog(CreateMessageDialogEx(Msg, DlgType, Buttons, DefaultIndex, CancelIndex, 80, 23, AOwner));
  Dialog := TMessageForm(CreateMessageDialog(Msg, DlgType, Buttons, DefaultIndex, CancelIndex, HelpIndex, AOwner));
  with Dialog do
  begin
    try
      if MsgTitle <> '' then
      begin
        Caption := MsgTitle;
      end;
      HelpContext := HelpCtx;
      HelpFile := HelpFileName;
      if X >= 0 then
        Left := X;
      if Y >= 0 then
        Top := Y;
      if (X < 0) and (Y < 0) then
      begin
        if (AOwner <> nil) and (AOwner is TWinControl) and TWinControl(AOwner).Visible then
        begin
          Position := poOwnerFormCenter;
        end
        else
        begin
          if MessageDlgToMainFormCenter and (Application.MainForm <> nil) and Application.MainForm.Visible then
          begin
            Position := poMainFormCenter;
          end
          else
          begin
            Position := poScreenCenter;
          end;
        end;
      end;
      Application.NormalizeAllTopMosts;
      try
        Result := ShowModal;
        if IsSysCDMClose then
        begin
          Result := CancelIndex;
          if Result < 0 then
          begin
            Result := DefaultIndex;
          end;
          if Result < 0 then
          begin
            Result := High(Buttons);
          end;
        end;
      finally
        Application.RestoreTopMosts;
      end;
    finally
      Free;
    end;
  end;
end;

{ TaskDialog based message dialog; requires Windows Vista or later }

type
  TWndProcCB = function (hwnd: HWND; iMsg: UINT; wParam:WPARAM; lParam: LPARAM): LRESULT; stdcall;

  TTaskMessageDialog = class(TCustomTaskDialog)
  private
    FHelpFile: string;
    FParentWnd: HWND;
    FPosition: TPoint;
    FCanceled: Boolean;
    FCancelIndex: Integer;
    FButtonClicked: Boolean;
    FWndProcCB: Pointer;
    FOldWndProcCB: Pointer;
  strict protected
    procedure DoOnButtonClicked(AModalResult: Integer; var CanClose: Boolean); override;
    procedure DoOnDialogCreated; override;
    procedure DoOnHelp; override;
  protected
    function CallbackProc(hwnd: HWND; msg: UINT; wParam: WPARAM;
      lParam: LPARAM; lpRefData: LONG_PTR): HResult; override;
  public
    AOwner: TComponent;
    function Execute(ParentWnd: HWND): Boolean; overload; override;
    property HelpFile: string read FHelpFile write FHelpFile;
    property Position: TPoint read FPosition write FPosition;
    property Canceled: Boolean read FCanceled;
  end;

var
  TaskMessageDialogList: TList<TTaskMessageDialog>;

procedure InitTaskMessageDialogList;
begin
  if (TaskMessageDialogList = nil) then
  begin
    TaskMessageDialogList := TList<TTaskMessageDialog>.Create;
  end;
  TaskMessageDialogList.Clear;
end;

procedure UnInitTaskMessageDialogList;
begin
  if (TaskMessageDialogList <> nil) then
  begin
    TaskMessageDialogList.Clear;
    FreeAndNil(TaskMessageDialogList);
  end;
end;

function WndProcForTaskForm(hwnd: HWND; iMsg: UINT; wParam:WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
  i: Integer;
  AForm: TTaskMessageDialog;
  AWMsg: TMessage;
begin
  for i := 0 to TaskMessageDialogList.Count - 1 do
  begin
    AForm := nil;
    if (TaskMessageDialogList.Items <> nil) and (TaskMessageDialogList.Items is TTaskMessageDialog) then
    begin
      AForm := TaskMessageDialogList.Items;
    end;
    if (AForm <> nil) and (AForm.Handle = hwnd) and
      Assigned(AForm.FOldWndProcCB) then
    begin
      if (iMsg = WM_COMMAND) then
      begin
        AWMsg.Msg := iMsg;
        AWMsg.WParam := wParam;
        AWMsg.LParam := lParam;
        AWMsg.Result := Result;
        if TWMCommand(AWMsg).ItemID = 2 then //和实体按钮无关,就是 ESC 按下了。
        begin
          iMsg := WM_NULL;
          try
            if (AForm.FCancelIndex > 0) and (AForm.FCancelIndex <= AForm.Buttons.Count) and
              (AForm.Buttons[AForm.FCancelIndex - 1].Enabled) and (IsWindowVisible(hwnd))then
            begin
              AForm.Buttons[AForm.FCancelIndex - 1].Click;
            end;
          except
          end;
        end;
      end;
      Result := TWndProcCB(AForm.FOldWndProcCB)(hwnd, iMsg, wParam, lParam);
    end;
  end;
end;

function TTaskMessageDialog.CallbackProc(hwnd: HWND; msg: UINT; wParam: WPARAM;
      lParam: LPARAM; lpRefData: LONG_PTR): HResult;
begin
  if msg = TDN_DIALOG_CONSTRUCTED then
  begin
    TaskMessageDialogList.Add(Self);
    FOldWndProcCB := Pointer(GetWindowLongW(hwnd, GWL_WNDPROC));
    FWndProcCB := Addr(WndProcForTaskForm);
    SetWindowLongW(hwnd, GWL_WNDPROC, IntPtr(FWndProcCB));
  end;
  if msg = TDN_DESTROYED then
  begin
    TaskMessageDialogList.Remove(Self);
    if Assigned(FOldWndProcCB) then
    begin
      SetWindowLongW(hwnd, GWL_WNDPROC, IntPtr(FOldWndProcCB));
    end;
  end;
  Result := inherited;
end;

const
  tdbHelp = -1;

procedure TTaskMessageDialog.DoOnButtonClicked(AModalResult: Integer; var CanClose: Boolean);
begin
  if AModalResult = tdbHelp then
  begin
    CanClose := False;
    DoOnHelp;
  end;
  FButtonClicked := True;
end;

procedure TTaskMessageDialog.DoOnDialogCreated;
var
  Rect: TRect;
  LX, LY: Integer;
  LHandle: HMONITOR;
  LMonitorInfo: TMonitorInfo;
  pt: TPoint;
begin
  LX := Position.X;
  LY := Position.Y;
  LHandle := MonitorFromWindow(FParentWnd, MONITOR_DEFAULTTONEAREST);
  LMonitorInfo.cbSize := SizeOf(LMonitorInfo);
  if GetMonitorInfo(LHandle, {$IFNDEF CLR}@{$ENDIF}LMonitorInfo) then
    with LMonitorInfo do
    begin
      GetWindowRect(Handle, Rect);
      if LX < 0 then
        LX := ((rcWork.Right - rcWork.Left) - (Rect.Right - Rect.Left)) div 2;
      if LY < 0 then
        LY := ((rcWork.Bottom - rcWork.Top) - (Rect.Bottom - Rect.Top)) div 2;
      Inc(LX, rcWork.Left);
      Inc(LY, rcWork.Top);
      if (Position.X < 0) and (Position.Y < 0) then
      begin
        if (AOwner <> nil) and (AOwner is TWinControl) and TWinControl(AOwner).Visible then
        begin
          // Position := poOwnerFormCenter;
          LX := ((TWinControl(AOwner).ClientRect.Right - TWinControl(AOwner).ClientRect.Left) -
            (Rect.Right - Rect.Left)) div 2;
          LY := ((TWinControl(AOwner).ClientRect.Bottom - TWinControl(AOwner).ClientRect.Top) -
            (Rect.Bottom - Rect.Top)) div 2;
          pt := TWinControl(AOwner).ClientToScreen(TPoint.Create(LX, LY));
          LX := pt.X;
          LY := pt.Y;
        end
        else
        begin
          if MessageDlgToMainFormCenter and (Application.MainForm <> nil) and Application.MainForm.Visible then
          begin
            // Position := poMainFormCenter;
            LX := ((Application.MainForm.ClientRect.Right - Application.MainForm.ClientRect.Left) -
              (Rect.Right - Rect.Left)) div 2;
            LY := ((Application.MainForm.ClientRect.Bottom - Application.MainForm.ClientRect.Top) -
              (Rect.Bottom - Rect.Top)) div 2;
            pt := TWinControl(AOwner).ClientToScreen(TPoint.Create(LX, LY));
            LX := pt.X;
            LY := pt.Y;
          end
          else
          begin
            // Position := poScreenCenter;
          end;
        end;
      end;
      SetWindowPos(Handle, 0, LX, LY, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
    end;
  if MessageDlgUseMessageBoxSysCMDColse and (Buttons.Count > 1) then
    EnableMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, MF_DISABLED or MF_GRAYED or MF_BYCOMMAND);
end;

procedure TTaskMessageDialog.DoOnHelp;
var
  LHelpFile: string;
  LHelpSystem: IHelpSystem;
begin
  if HelpContext <> 0 then
  begin
    if FHelpFile = '' then
      LHelpFile := Application.HelpFile
    else
      LHelpFile := HelpFile;
    if System.HelpIntfs.GetHelpSystem(LHelpSystem) then
      try
        LHelpSystem.Hook(Application.Handle, LHelpFile, HELP_CONTEXT, HelpContext);
      except
        on E: Exception do
          ShowHelpException(E);
      end;
  end;
end;

function TTaskMessageDialog.Execute(ParentWnd: HWND): Boolean;
begin
  FParentWnd := ParentWnd;
  Result := inherited Execute(ParentWnd);
  if (not FButtonClicked) and Result then
  begin
    ModalResult := FCancelIndex;
  end;
end;

const
  tdiConfirm = 32514;
  tdiStop = tdiError;

function DoTaskMessageDlgPosHelp(const Instruction, Msg, MsgTitle: string; DlgType: TMsgDlgType;
  const Buttons: array of string; const DefaultIndex, CancelIndex, HelpIndex: Integer; HelpCtx: LongInt;
  const HelpFileName: string; const X, Y: Integer; const AOwner: TComponent = nil): Integer;
const
  IconMap: array [TMsgDlgType] of TTaskDialogIcon =
  // (tdiWarning, tdiError, tdiInformation, tdiConfirm, tdiStop, tdiNone);
    (tdiWarning, tdiError, tdiInformation, tdiConfirm, tdiNone);
var
  i: Integer;
  LTaskDialog: TTaskMessageDialog;
begin
  Application.ModalStarted;
  LTaskDialog := TTaskMessageDialog.Create(nil);
  try
    LTaskDialog.FButtonClicked := False;
    //为 TAST 对话框增加 ESC 按下的默认按钮。
    //LTaskDialog.FCancelIndex := 2;
    LTaskDialog.FCancelIndex := -1;
    if CancelIndex > 0 then
    begin
      LTaskDialog.FCancelIndex := CancelIndex;
    end;
    // Assign buttons
    for i := Low(Buttons) to High(Buttons) do
    begin
      with LTaskDialog.Buttons.Add do
      begin
        Caption := Buttons;
        if i + 1 = DefaultIndex then
          Default := True;
        // if i + 1 = CancelIndex then
        // Cancel := True;
        ModalResult := i + 1;
      end;
    end;
    LTaskDialog.AOwner := AOwner;
    // Set dialog properties
    with LTaskDialog do
    begin
      if DlgType <> mtCustom then
{$IF DEFINED(CLR)}
        Caption := Captions[DlgType]
{$ELSE}
        Caption := LoadResString(Captions[DlgType])
{$IFEND}
      else
        Caption := Application.Title;
      if MsgTitle <> '' then
      begin
        Caption := MsgTitle;
      end;
      CommonButtons := [];
      if Application.UseRightToLeftReading then
        Flags := Flags + [tfRtlLayout];
      HelpContext := HelpCtx;
      HelpFile := HelpFileName;
      MainIcon := IconMap[DlgType];
      Position := Point(X, Y);
      Text := Msg;
      Title := Instruction;
    end;

    // Show dialog and return result
    Result := mrNone;
    if LTaskDialog.Execute then
      Result := LTaskDialog.ModalResult;
  finally
    LTaskDialog.Free;
    Application.ModalFinished;
  end;
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function ShowMessageDlgPosHelp(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex, HelpIndex: Integer; HelpCtx: LongInt; const HelpFileName: string;
  const X, Y: Integer; const AOwner: TComponent = nil): Integer;
begin
  if TOSVersion.Check(6) and UseLatestCommonDialogs and StyleServices.Enabled and StyleServices.IsSystemStyle then
    Result := DoTaskMessageDlgPosHelp('', Msg, MsgTitle, DlgType, Buttons, DefaultIndex, CancelIndex, HelpIndex,
      HelpCtx, HelpFileName, X, Y, AOwner)
  else
    Result := DoMessageDlgPosHelp(Msg, MsgTitle, DlgType, Buttons, DefaultIndex, CancelIndex, HelpIndex, HelpCtx,
      HelpFileName, X, Y, AOwner)
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function MessageDlgHelp(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex, HelpIndex: Integer; HelpCtx: LongInt; const HelpFileName: string;
  const AOwner: TComponent = nil): Integer;
begin
  Result := ShowMessageDlgPosHelp(Msg, MsgTitle, DlgType, Buttons, DefaultIndex, CancelIndex, HelpIndex, HelpCtx,
    HelpFileName, -1, -1, AOwner);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function MessageDlgPos(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex: Integer; const X, Y: Integer; const AOwner: TComponent = nil): Integer;
begin
  Result := ShowMessageDlgPosHelp(Msg, MsgTitle, DlgType, Buttons, DefaultIndex, CancelIndex, -1, 1, '', X, Y, AOwner);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function MessageDialog(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const DefaultIndex, CancelIndex: Integer; const AOwner: TComponent = nil): Integer;
begin
  Result := MessageDlgPos(Msg, MsgTitle, DlgType, Buttons, DefaultIndex, CancelIndex, -1, -1, AOwner);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function MessageDialog(const Msg, MsgTitle: string; const DlgType: TMsgDlgType; const Buttons: array of string;
  const AOwner: TComponent = nil): Integer;
begin
  Result := MessageDialog(Msg, MsgTitle, dlgType, Buttons, 1, -1, AOwner);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function QuestionDialog(const Msg, MsgTitle: string; const AOwner: TComponent = nil; YesCaption: string = '';
  NoCaption: string = ''): Boolean;
var
  FYesCaption, FNoCaption: string;
begin
  FYesCaption := YesCaption;
  FNoCaption := NoCaption;
  if FYesCaption = '' then
  begin
    FYesCaption := '是(&Y)';
  end;
  if FNoCaption = '' then
  begin
    FNoCaption := '否(&N)';
  end;
  Result := MessageDialog(Msg, MsgTitle, mtConfirmation, [FYesCaption, FNoCaption], 1, 2, AOwner) = 1;
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function QuestionCancelDialog(const Msg, MsgTitle: string; const AOwner: TComponent = nil; YesCaption: string = '';
  NoCaption: string = ''; CancelCaption: string = ''): Integer;
var
  FYesCaption, FNoCaption, FCancelCaption: string;
begin
  FYesCaption := YesCaption;
  FNoCaption := NoCaption;
  FCancelCaption := CancelCaption;
  if FYesCaption = '' then
  begin
    FYesCaption := '是(&Y)';
  end;
  if FNoCaption = '' then
  begin
    FNoCaption := '否(&N)';
  end;
  if FCancelCaption = '' then
  begin
    FCancelCaption := '取消(&C)';
  end;
  Result := MessageDialog(Msg, MsgTitle, mtConfirmation, [FYesCaption, FNoCaption, FCancelCaption], 1, 3, AOwner);
  case Result of
    1:
      begin
        Result := mrYes;
      end;
    2:
      begin
        Result := mrNo;
      end;
  else
    begin
      Result := mrCancel;
    end;
  end;
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowMessagePos(const Msg, MsgTitle: string; const X, Y: Integer; const AOwner: TComponent = nil;
  OKCaption: string = '');
var
  FOKCaption: string;
begin
  FOKCaption := OKCaption;
  if FOKCaption = '' then
  begin
    FOKCaption := '确定(&O)';
  end;
  MessageDlgPos(Msg, MsgTitle, mtInformation, [FOKCaption], 1, -1, X, Y, AOwner);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowMessage(const Msg, MsgTitle: string; const AOwner: TComponent = nil; OKCaption: string = '');
begin
  ShowMessagePos(Msg, MsgTitle, -1, -1, AOwner, OKCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowMessage(const Msg: string; const AOwner: TComponent = nil; OKCaption: string = '');
begin
  ShowMessage(Msg, Application.Title, AOwner, OKCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowWarning(const Msg, MsgTitle: string; const AOwner: TComponent = nil; OKCaption: string = '');
var
  FOKCaption: string;
begin
  FOKCaption := OKCaption;
  if FOKCaption = '' then
  begin
    FOKCaption := '确定(&O)';
  end;
  MessageDlgPos(Msg, MsgTitle, mtWarning, [FOKCaption], 1, -1, -1, -1, AOwner);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowWarning(const Msg: string; const AOwner: TComponent = nil; OKCaption: string = '');
begin
  ShowWarning(Msg, Application.Title, AOwner, OKCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowError(const Msg, MsgTitle: string; const AOwner: TComponent = nil; OKCaption: string = '');
var
  FOKCaption: string;
begin
  FOKCaption := OKCaption;
  if FOKCaption = '' then
  begin
    FOKCaption := '确定(&O)';
  end;
  MessageDlgPos(Msg, MsgTitle, mtError, [FOKCaption], 1, -1, -1, -1, AOwner);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowError(const Msg: string; const AOwner: TComponent = nil; OKCaption: string = '');
begin
  ShowMessage(Msg, Application.Title, AOwner, OKCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowException(E: Exception; const AOwner: TComponent = nil; OKCaption: string = '');
var
  Msg: string;
begin
  Msg := E.Message;
  if (Msg <> '') and (AnsiLastChar(Msg) > '.') then
    Msg := Msg + '.';
  ShowException(Msg, AOwner, OKCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
procedure ShowException(E: string; const AOwner: TComponent = nil; OKCaption: string = '');
var
  FOKCaption: string;
begin
  FOKCaption := OKCaption;
  if FOKCaption = '' then
  begin
    FOKCaption := '确定(&O)';
  end;
  MessageDlgPos(E, Application.Title, mtError, [FOKCaption], 1, -1, -1, -1, AOwner);
end;

//

type
  TInputQueryForm = class(TForm)
  public
    FCloseQueryFunc: TFunc<Boolean>;
    function CloseQuery: Boolean; override;
    procedure DoShow; override;
  end;

function TInputQueryForm.CloseQuery: Boolean;
begin
  Result := (ModalResult = mrCancel) or (not Assigned(FCloseQueryFunc)) or FCloseQueryFunc();
end;

procedure TInputQueryForm.DoShow;
begin
  if MessageDlgInputQueryDisableSysCMDClose then
  begin
    EnableMenuItem(GetSystemMenu(Handle, False), SC_CLOSE, MF_DISABLED or MF_GRAYED or MF_BYCOMMAND);
  end;
  inherited;
end;

{ Input dialog }

function GetTextBaseline(AControl: TControl; ACanvas: TCanvas): Integer;
var
  tm: TTextMetric;
  ClientRect: TRect;
  Ascent: Integer;
begin
  ClientRect := AControl.ClientRect;
  GetTextMetrics(ACanvas.Handle, tm);
  Ascent := tm.tmAscent + 1;
  Result := ClientRect.Top + Ascent;
  Result := AControl.Parent.ScreenToClient(AControl.ClientToScreen(TPoint.Create(0, Result))).Y - AControl.Top;
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQueryPosHelp(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; HelpCtx: LongInt; const HelpFileName: string; CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil;
  const AOwner: TComponent = nil; OKCaption: string = ''; CancelCaption: string = ''): Boolean;
var
  I, J: Integer;
  Form: TInputQueryForm;
  Prompt: TLabel;
  Edit: TEdit;
  DialogUnits: TPoint;
  PromptCount, CurPrompt: Integer;
  MaxPromptWidth: Integer;
  ButtonTop, ButtonWidth, ButtonHeight: Integer;

  function GetPromptCaption(const ACaption: string): string;
  begin
    if (Length(ACaption) > 1) and (ACaption[1] < #32) then
      Result := Copy(ACaption, 2, MaxInt)
    else
      Result := ACaption;
  end;

  function GetMaxPromptWidth(Canvas: TCanvas): Integer;
  var
    I: Integer;
    LLabel: TLabel;
  begin
    Result := 0;
    // Use a TLabel rather than an API such as GetTextExtentPoint32 to
    // avoid differences in handling characters such as line breaks.
    LLabel := TLabel.Create(nil);
    try
      for I := 0 to PromptCount - 1 do
      begin
        LLabel.Caption := GetPromptCaption(APrompts[I]);
        Result := Max(Result, LLabel.Width + DialogUnits.X);
      end;
    finally
      LLabel.Free;
    end;
  end;

  function GetPasswordChar(const ACaption: string): Char;
  begin
    if (Length(ACaption) > 1) and (ACaption[1] < #32) then
      Result := '*'
    else
      Result := #0;
  end;

begin
  if Length(AValues) < Length(APrompts) then
    raise EInvalidOperation.CreateRes(@SPromptArrayTooShort);
  PromptCount := Length(APrompts);
  if PromptCount < 1 then
    raise EInvalidOperation.CreateRes(@SPromptArrayEmpty);
  Result := False;
  if (AOwner <> nil) then
  begin
    Form := TInputQueryForm.CreateNew(AOwner);
  end
  else
  begin
    Form := TInputQueryForm.CreateNew(Application);
  end;
  with Form do
  begin
    try
      if MessageDlgFormUseDefaultFont then
      begin
        Font.Name := MessageDlgDefaultFormFontName;
        Font.Size := MessageDlgDefaultFormFontSize;
      end;
      FCloseQueryFunc := function: Boolean
        var
          I, J: Integer;
          LValues: array of string;
          Control: TControl;
        begin
          Result := True;
          if Assigned(CloseQueryFunc) then
          begin
            SetLength(LValues, PromptCount);
            J := 0;
            for I := 0 to Form.ControlCount - 1 do
            begin
              Control := Form.Controls[I];
              if Control is TEdit then
              begin
                LValues[J] := TEdit(Control).Text;
                Inc(J);
              end;
            end;
            Result := CloseQueryFunc(LValues,  Form);
            Form.BringToFront;
          end;
        end;
      Canvas.Font := Font;
      Font.Charset := GetDefFontCharSet;
      DialogUnits := GetAveCharSize(Canvas);
      MaxPromptWidth := GetMaxPromptWidth(Canvas);
      BorderStyle := bsDialog;
      Caption := ACaption;
      ClientWidth := MulDiv(180 + MaxPromptWidth, DialogUnits.X, 4);
      PopupMode := pmAuto;
      HelpContext := HelpCtx;
      HelpFile := HelpFileName;
      Position := poDefault;
      if X >= 0 then
        Left := X;
      if Y >= 0 then
        Top := Y;
      if (X < 0) and (Y < 0) then
      begin
        if (AOwner <> nil) and (AOwner is TWinControl) and TWinControl(AOwner).Visible then
        begin
          Position := poOwnerFormCenter;
        end
        else
        begin
          if MessageDlgToMainFormCenter and (Application.MainForm <> nil) and Application.MainForm.Visible then
          begin
            Position := poMainFormCenter;
          end
          else
          begin
            Position := poScreenCenter;
          end;
        end;
      end;
      CurPrompt := MulDiv(8, DialogUnits.Y, 8);
      Edit := nil;
      for I := 0 to PromptCount - 1 do
      begin
        Prompt := TLabel.Create(Form);
        with Prompt do
        begin
          Font.Name := MessageDlgDefaultFontName;
          Font.Size := MessageDlgDefaultFontSize;
          Parent := Form;
          Caption := GetPromptCaption(APrompts[I]);
          Left := MulDiv(8, DialogUnits.X, 4);
          Top := CurPrompt;
          Constraints.MaxWidth := MaxPromptWidth;
          WordWrap := True;
        end;
        Edit := TEdit.Create(Form);
        with Edit do
        begin
          Font.Name := MessageDlgDefaultFontName;
          Font.Size := MessageDlgDefaultFontSize;
          Parent := Form;
          PasswordChar := GetPasswordChar(APrompts[I]);
          Left := Prompt.Left + MaxPromptWidth;
          Top := Prompt.Top + Prompt.Height - DialogUnits.Y -
            (GetTextBaseline(Edit, Canvas) - GetTextBaseline(Prompt, Canvas));
          Width := Form.ClientWidth - Left - MulDiv(8, DialogUnits.X, 4);
          MaxLength := 255;
          Text := AValues[I];
          SelectAll;
          Prompt.FocusControl := Edit;
        end;
        CurPrompt := Edit.Top + Edit.Height + 5;
      end;
      ButtonTop := Edit.Top + Edit.Height + 15;
      ButtonWidth := MulDiv(50, DialogUnits.X, 4);
      ButtonHeight := MulDiv(14, DialogUnits.Y, 8);
      with TButton.Create(Form) do
      begin
        Parent := Form;
        Caption := SMsgDlgOK;
        Font.Name := MessageDlgDefaultFontName;
        Font.Size := MessageDlgDefaultFontSize;
        Caption := OKCaption;
        if Caption = '' then
        begin
          Caption := '确定(&O)';
        end;
        ModalResult := mrOk;
        Default := True;
        SetBounds(Form.ClientWidth - (ButtonWidth + MulDiv(8, DialogUnits.X, 4)) * 2, ButtonTop, ButtonWidth,
          ButtonHeight);
      end;
      with TButton.Create(Form) do
      begin
        Parent := Form;
        Caption := SMsgDlgCancel;
        Caption := CancelCaption;
        if Caption = '' then
        begin
          Caption := '取消(&C)';
        end;
        ModalResult := mrCancel;
        Cancel := True;
        SetBounds(Form.ClientWidth - (ButtonWidth + MulDiv(8, DialogUnits.X, 4)), ButtonTop, ButtonWidth, ButtonHeight);
        Form.ClientHeight := Top + Height + 13;
      end;
      Application.NormalizeAllTopMosts;
      try
        if ShowModal = mrOk then
        begin
          J := 0;
          for I := 0 to ControlCount - 1 do
            if Controls[I] is TEdit then
            begin
              Edit := TEdit(Controls[I]);
              AValues[J] := Edit.Text;
              Inc(J);
            end;
          Result := True;
        end;
      finally
        Application.RestoreTopMosts;
      end;
    finally
      Form.Free;
    end;
  end;
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQueryPosHelp(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; HelpCtx: LongInt; const HelpFileName: string; CloseQueryEvent: TMessageDlgCNInputCloseQueryEvent;
  Context: TObject = nil; const AOwner: TComponent = nil; OKCaption: string = ''; CancelCaption: string = ''): Boolean;
var
  Func: TMessageDlgCNInputCloseQueryFunc;
begin
  Func := function(const Values: array of string; QueryForm: TForm): Boolean // 注意本行最后不能有 ; 号
    begin
      Result := True;
      CloseQueryEvent(Context, Values, Result, QueryForm);
    end;
  Result := InputQueryPosHelp(ACaption, APrompts, AValues, -1, -1, HelpCtx, HelpFileName, Func, AOwner, OKCaption,
    CancelCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQueryPos(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean;
begin
  Result := InputQueryPosHelp(ACaption, APrompts, AValues, -1, -1, -1, '', CloseQueryFunc, AOwner, OKCaption,
    CancelCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQueryPos(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  const X, Y: Integer; CloseQueryEvent: TMessageDlgCNInputCloseQueryEvent; Context: TObject = nil; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean;
begin
  Result := InputQueryPosHelp(ACaption, APrompts, AValues, X, Y, -1, '', CloseQueryEvent, Context, AOwner, OKCaption,
    CancelCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQuery(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil; const AOwner: TComponent = nil; OKCaption: string = '';
  CancelCaption: string = ''): Boolean;
begin
  Result := InputQueryPos(ACaption, APrompts, AValues, -1, -1, CloseQueryFunc, AOwner, OKCaption, CancelCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQuery(const ACaption: string; const APrompts: array of string; var AValues: array of string;
  CloseQueryEvent: TMessageDlgCNInputCloseQueryEvent; Context: TObject = nil; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean;
begin
  Result := InputQueryPos(ACaption, APrompts, AValues, -1, -1, CloseQueryEvent, Context, AOwner, OKCaption,
    CancelCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQuery(const ACaption, APrompt: string; var Value: string; const AOwner: TComponent = nil;
  CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean;
var
  Values: array [0 .. 0] of string;
begin
  Values[0] := Value;
  Result := InputQuery(ACaption, [APrompt], Values, CloseQueryFunc, AOwner, OKCaption, CancelCaption);
  if Result then
    Value := Values[0];
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputBox(const ACaption, APrompt, ADefault: string; const AOwner: TComponent = nil;
  CloseQueryFunc: TMessageDlgCNInputCloseQueryFunc = nil;
  OKCaption: string = ''; CancelCaption: string = ''): string;
begin
  Result := ADefault;
  InputQuery(ACaption, APrompt, Result, AOwner, CloseQueryFunc, OKCaption, CancelCaption);
end;

//[UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.SafeSubWindows)]
function InputQueryEx(const ACaption, APrompt: string; var Value: string; const AOwner: TComponent = nil;
  OKCaption: string = ''; CancelCaption: string = ''): Boolean;
  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;

var
  Form: TForm;
  Prompt: TLabel;
  Edit: TEdit;
  DialogUnits: TPoint;
  ButtonTop, ButtonWidth, ButtonHeight: Integer;
begin
  Result := False;
  if (AOwner <> nil) then
  begin
    Form := TForm.Create(AOwner);
  end
  else
  begin
    Form := TForm.Create(Application);
  end;
  with Form do
    try
      Font.Name := MessageDlgDefaultFormFontName;
      Font.Size := MessageDlgDefaultFormFontSize;
      Canvas.Font := Font;
      DialogUnits := GetAveCharSize(Canvas);
      BorderStyle := bsDialog;
      Caption := ACaption;
      ClientWidth := MulDiv(180, DialogUnits.X, 4);
      Position := poDefault;
      if (AOwner <> nil) and (AOwner is TWinControl) and TWinControl(AOwner).Visible then
      begin
        Position := poOwnerFormCenter;
      end
      else
      begin
        if MessageDlgToMainFormCenter and (Application.MainForm <> nil) and Application.MainForm.Visible then
        begin
          Position := poMainFormCenter;
        end
        else
        begin
          Position := poScreenCenter;
        end;
      end;
      Prompt := TLabel.Create(Form);
      with Prompt do
      begin
        Parent := Form;
        Font.Name := MessageDlgDefaultFontName;
        Font.Size := MessageDlgDefaultFontSize;
        Caption := APrompt;
        Left := MulDiv(8, DialogUnits.X, 4);
        Top := MulDiv(8, DialogUnits.Y, 8);
        Constraints.MaxWidth := MulDiv(164, DialogUnits.X, 4);
        WordWrap := True;
      end;
      Edit := TEdit.Create(Form);
      with Edit do
      begin
        Parent := Form;
        Font.Name := MessageDlgDefaultFontName;
        Font.Size := MessageDlgDefaultFontSize;
        Left := Prompt.Left;
        Top := Prompt.Top + Prompt.Height + 5;
        Width := MulDiv(164, DialogUnits.X, 4);
        MaxLength := 255;
        Text := Value;
        SelectAll;
      end;
      ButtonTop := Edit.Top + Edit.Height + 15;
      ButtonWidth := MulDiv(50, DialogUnits.X, 4);
      ButtonHeight := MulDiv(18, DialogUnits.Y, 8);
      with TButton.Create(Form) do
      begin
        Parent := Form;
        Font.Name := MessageDlgDefaultFontName;
        Font.Size := MessageDlgDefaultFontSize;
        Caption := OKCaption;
        if Caption = '' then
        begin
          Caption := '确定(&O)';
        end;
        ModalResult := mrOk;
        Default := True;
        SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth, ButtonHeight);
      end;
      with TButton.Create(Form) do
      begin
        Parent := Form;
        Font.Name := MessageDlgDefaultFontName;
        Font.Size := MessageDlgDefaultFontSize;
        Caption := CancelCaption;
        if Caption = '' then
        begin
          Caption := '取消(&C)';
        end;
        ModalResult := mrCancel;
        Cancel := True;
        SetBounds(MulDiv(92, DialogUnits.X, 4), Edit.Top + Edit.Height + 15, ButtonWidth, ButtonHeight);
        Form.ClientHeight := Top + Height + 13;
      end;
      Application.NormalizeAllTopMosts;
      try
        if ShowModal = mrOk then
        begin
          Value := Edit.Text;
          Result := True;
        end;
      finally
        Application.RestoreTopMosts;
      end;
    finally
      Form.Free;
    end;
end;

initialization
  InitTaskMessageDialogList;

finalization
  UnInitTaskMessageDialogList

end.[/mw_shl_code]

看到这里是不是已经很晕了?

那么再晕点也没关系了吧?

给出调用的代码吧。
游客,如果您要查看本帖隐藏内容请回复


好像 MessageBox 都可以做到,那么下面这个呢?

[mw_shl_code=delphi,true]function ShowRewriteQuestion(MessageToShow, Title: String; AOwner: TComponent = nil): Integer;
begin
  // Result := MessageDlg(MessageToShow, mtConfirmation, [mbYes, mbYesToAll, mbNo, mbNoToAll], 0);
  // exit;
  Result := MessageDlgCn.MessageDialog(MessageToShow, Title, mtConfirmation,
    ['是(&Y)', '全部是', '否(&N)', '全部否', '放弃'], 3, 5, AOwner);
  case Result of
    1:
      begin
        Result := mrYes;
      end;
    2:
      begin
        Result := mrYesToAll;
      end;
    3:
      begin
        Result := mrNo;
      end;
    4:
      begin
        Result := mrNoToAll;
      end;
  else
    begin
      Result := mrAbort;
    end;
  end;
end;[/mw_shl_code]


最后一个例子应该够大家使用了吧?

不过我这个单元还有一个好东西呢。

[mw_shl_code=delphi,true]function TFrm.InputQuery_Check_Name(const Values: array of string; QueryForm: TForm): Boolean;
begin
  Result := False;
  if Length(Values) > 0 then
  begin
    if Trim(Values[0]) = '' then
    begin
      CommUI.ShowError('名称不能为空!', QueryForm);
      Exit;
    end;
    if find then //find 您自己替换
    begin
      CommUI.ShowError('名称不能重复!', QueryForm);
      Exit;
    end;
  end;
  Result := True;
end;


if not MessageDlgCN.InputQuery('输入名称','请输入新的名称:',New_Name, Self, InputQuery_Check_Name) then Exit;[/mw_shl_code]

大家也可以不用我这个,用 DELPHI 自带的,但是要改 DELPHI 的 CONST.PAS ,才能显示中文,而且也不是很自由。



面对 FMX 如果您只想显示系统对话框,那么修改 FMX.Consts 是最简单有效的办法。
如果您打算显示自定义对话框。
那么可以使用 FMX.DialogHelper 里的 TDialogHelper 对象。但是 按钮依然是指定的哪几种。

如果想显示自定义的文字按钮对话框。
可以试试,下面的开源项目。
游客,如果您要查看本帖隐藏内容请回复

其中的 DEMO Test CHS TDialogBuilder 支持按钮文字自定义。




特别声明
禁止 win2003 (楚凡) QQ635887 使用本人修改的内容

禁止 qiuyan81 (苦恋树) QQ46494153 使用本人修改的内容。

禁止 gfuchao  QQ82715485 使用本人修改的内容。

禁止 supersk QQ未知,使用本人修改的内容。

禁止 yesin119 QQ未知,使用本人修改的内容。

禁止 263378440 使用本人修改的内容。

禁止 yanse 使用本人修改的内容。

禁止 ltshdp、ltsh、(禁卫军) 使用本人修改的内容

禁止 www123 使用本人修改的内容

禁止 eliyh 使用本人修改的内容

禁止 zwjchinazwj (蒲石) 使用本人修改的内容

禁止 zhipu QQ:2001972  使用本人修改的内容

禁止 jackalan (nVicen) QQ:875271757  使用本人修改的内容

禁止 kencc2016 (小宇) QQ:2601759381 使用本人修改的内容

以上用户名均为 2CCC 的

禁止 QQ:191909837 使用本人修改的内容
禁止 QQ 81604691 使用本人修改的版内容
禁止 QQ:122742470(菜根) 使用本人修改或建立的代码或工具。

当然,如果你们脸皮比较厚,就偷偷的用吧。

凡是想要骂我的,都可以偷偷的用,反正我是控制不了。
只要你们不鄙视自己就行。
(C)(P)Flying Wang
回复

使用道具 举报

1

主题

43

帖子

1193

积分

金牌会员

Rank: 6Rank: 6

积分
1193
沙发
发表于 2018-1-17 06:16:00 | 只看该作者
京东数码购物支持本站
感谢分享,先收藏了!
回复 支持 反对

使用道具 举报

0

主题

3

帖子

10

积分

新手上路

Rank: 1

积分
10
地板
发表于 2018-3-15 09:06:16 | 只看该作者
京东数码购物支持本站
难得  查看地一一下代码
回复 支持 反对

使用道具 举报

0

主题

21

帖子

68

积分

注册会员

Rank: 2

积分
68
6#
发表于 2018-7-4 17:50:34 | 只看该作者
京东数码购物支持本站
GGGGGGGGGGGGGGGGG
回复 支持 反对

使用道具 举报

0

主题

17

帖子

80

积分

注册会员

Rank: 2

积分
80
7#
发表于 2018-8-8 08:33:34 | 只看该作者
京东数码购物支持本站
厉害,但是看不懂!菜鸟一枚
回复 支持 反对

使用道具 举报

0

主题

6

帖子

30

积分

新手上路

Rank: 1

积分
30
9#
发表于 2018-12-22 01:55:52 | 只看该作者
京东数码购物支持本站
学习下学习下学习下
回复 支持 反对

使用道具 举报

1

主题

43

帖子

1193

积分

金牌会员

Rank: 6Rank: 6

积分
1193
10#
发表于 2018-12-26 01:40:15 | 只看该作者
京东数码购物支持本站
感谢分享,收藏了!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|新时代Pascal论坛

GMT+8, 2024-4-29 05:41 , Processed in 0.081887 second(s), 23 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表