【问题标题】:What is the best way in Delphi to show customized Message Dialogs?Delphi 中显示自定义消息对话框的最佳方式是什么?
【发布时间】:2009-07-08 19:26:09
【问题描述】:

我正在使用 Delphi,我想在 MessageDlg as described here 的按钮中显示自定义文本。最好的方法是什么?

【问题讨论】:

    标签: delphi user-interface


    【解决方案1】:

    回答我自己的问题....我编写了以下对我很有效的单元。

    Delphi 提供CreateMessageDialog() 为您提供对话框模板,您可以在显示之前对其进行修改。我用它创建了一个名为 MessageDlgCustom 的函数,它采用与标准 MessageDlg 相同的参数,但为替换按钮标题添加了一个。

    它可以正确处理自定义字体并自动调整按钮以使其足够宽以显示信息。如果按钮溢出对话框,那么它也会被调整。

    使用该单元后,以下示例有效:

    case MessageDlgCustom('Save your changes?',mtConfirmation,
      [mbYes,mbNo,mbCancel],
      ['&Yes, I would like to save them with this absurdly long button',
      '&No, I do not care about my stupid changes',
      '&Arg! What are you talking about?  Do not close the form!'],
      nil)  //nil = no custom font
    of
      mrYes:   
        begin
          SaveChanges;
          CloseTheForm;
        end;  //mrYes (save & close)
      mrNo: 
        begin
          CloseForm;
        end;  //mrNo (close w/o saving)
      mrCancel:
        begin
          //do nothing
        end;  //mrCancel (neither save nor close)
    end;  //case
    

    如果其他人知道更好的方法,请分享。

    unit CustomDialog;
    
    interface
    
    uses
      Dialogs, Forms, Graphics, StdCtrls;
    
    function MessageDlgCustom(const Msg: string; DlgType: TMsgDlgType;
      Buttons: TMsgDlgButtons; ToCaptions: array of string;
      customFont: TFont) : integer;
    procedure ModifyDialog(var frm: TForm; ToCaptions : array of string;
      customFont : TFont = nil);
    
    
    implementation
    
    uses
      Windows, SysUtils;
    
    function GetTextWidth(s: string; fnt: TFont; HWND: THandle): integer;
    var
      canvas: TCanvas;
    begin
      canvas := TCanvas.Create;
      try
        canvas.Handle := GetWindowDC(HWND);
        canvas.Font := fnt;
        Result := canvas.TextWidth(s);
      finally
        ReleaseDC(HWND,canvas.Handle);
        FreeAndNil(canvas);
      end;  //try-finally
    end;
    
    function MessageDlgCustom(const Msg: string;
      DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; ToCaptions: array of string;
      customFont: TFont): integer;
    var
      dialog : TForm;
    begin
      try
        dialog := CreateMessageDialog(Msg, DlgType, Buttons);
        dialog.Position := poScreenCenter;
        ModifyDialog(dialog,ToCaptions,customFont);
        Result := dialog.ShowModal;
      finally
        dialog.Release;
      end;  //try-finally
    end;
    
    procedure ModifyDialog(var frm: TForm; ToCaptions: array of string;
      customFont: TFont);
    const
      c_BtnMargin = 10;  //margin of button around caption text
    var
      i,oldButtonWidth,newButtonWidth,btnCnt : integer;
    begin
      oldButtonWidth := 0;
      newButtonWidth := 0;
      btnCnt := 0;
      for i := 0 to frm.ComponentCount - 1 do begin
        //if they asked for a custom font, assign it here
        if customFont <> nil then begin
          if frm.Components[i] is TLabel then begin
            TLabel(frm.Components[i]).Font := customFont;
          end;
          if frm.Components[i] is TButton then begin
            TButton(frm.Components[i]).Font := customFont;
          end;
        end;
        if frm.Components[i] is TButton then begin
          //check buttons for a match with a "from" (default) string
          //if found, replace with a "to" (custom) string
          Inc(btnCnt);
    
          //record the button width *before* we changed the caption
          oldButtonWidth := oldButtonWidth + TButton(frm.Components[i]).Width;
    
          //if a custom caption has been provided use that instead,
          //or just leave the default caption if the custom caption is empty
          if ToCaptions[btnCnt - 1]<>'' then
            TButton(frm.Components[i]).Caption := ToCaptions[btnCnt - 1];
    
          //auto-size the button for the new caption
          TButton(frm.Components[i]).Width :=
            GetTextWidth(TButton(frm.Components[i]).Caption,
              TButton(frm.Components[i]).Font,frm.Handle) + c_BtnMargin;
    
          //the first button can stay where it is.
          //all other buttons need to slide over to the right of the one b4.
          if (1 < btnCnt) and (0 < i) then begin
            TButton(frm.Components[i]).Left :=
              TButton(frm.Components[i-1]).Left +
              TButton(frm.Components[i-1]).Width + c_BtnMargin;
          end;
    
          //record the button width *after* changing the caption
          newButtonWidth := newButtonWidth + TButton(frm.Components[i]).Width;
        end;  //if TButton
      end;  //for i
    
      //whatever we changed the buttons by, widen / shrink the form accordingly
      frm.Width := Round(frm.Width + (newButtonWidth - oldButtonWidth) +
        (c_BtnMargin * btnCnt));
    end;
    
    end.
    

    【讨论】:

    • 好吧,如果您至少使用 Delphi 2007,那么我将创建一个全新的 MessageDlg() 函数,首先检查 Windows 版本,使用 Vista 上的新对话框类,然后使用修改后的版本否则原始 MessageDlg() 函数。这样您也可以轻松添加“不再显示”复选框。
    • 目前的代码无法编译。您需要重新组织几个方法。 GetTextWidth 需要向上移动到实现的顶部,如果在实现中将 ModifiyDialog 移动到 MessageDlgCustom 方法的上方,则可以从接口部分中删除声明。在 WinXP 上,修改后的对话框最后一个按钮,使用您的示例调用几乎位于窗口边框的边缘。由于某种原因,该方法没有正确地重新计算对话框的宽度。
    • @Ryan - 谢谢,我重新组织它以将最重要的东西放在顶部,忘记了它会破坏编译。我已经恢复了原来的顺序。它现在应该编译。我必须在 XP 机器上试一试——我使用的是 Vista。希望你描述的问题只发生在极端情况下,无论如何......
    • 这个答案的关键是 VCL 的 CreateMessageDialog 函数,它提供了一个常用的对话框对象供您在显示之前进行修改。请在开始时提及,而不是让读者深入研究示例以找到它的零宣传用法。
    • 我建议进行编辑,以处理您不想覆盖所有按钮的情况。像MessageDlgCustom('Confirm?',mtCustom, mbYesNoCancel, ['Yes, sir!','',''], nil); 一样,将使用默认值而不是空字符串。请检查它。
    【解决方案2】:

    作为替代方案,您可以使用开源SynTaskDialog 单元。 SynTaskDialog 在较新的 Windows 版本上本机使用 Windows TaskDialog API,并在旧版本上模拟它。你甚至可以use it with FireMonkey

    有关可自定义 MessageDlg 函数的示例,请查看 this answer

    【讨论】:

      【解决方案3】:

      您可以查看 GitHub (https://github.com/digao-dalpiaz/Dam) 上提供的 TDam 组件。

      此组件允许您使用预定义按钮创建自定义消息对话框,使用格式化文本(HTML 文本),并允许自定义对话框的许多方面。

      除此之外,您可以将所有应用程序对话框管理到一个“容器”中,该容器将所有对话框存储为对象 (TDamMsg)。

      TDam Message Example

      TDamMsg 属性允许自定义消息对话框,例如:

      • Button1 - 按钮 1 标题
      • Button2 - 按钮 2 标题
      • Button3 - 按钮 3 标题

      按钮:TDamMsgButtons = 定义消息对话框中的按钮:

      • dbOK:定义一键OK
      • dbYesNo:定义两个按钮是/否
      • dbOne:通过Button1定义的标题定义一个按钮
      • dbTwo:通过Button1和Button2定义的标题定义了两个按钮
      • dbThree:通过Button1、Button2和Button3定义的字幕定义了三个按钮

      【讨论】:

        【解决方案4】:

        另外,请确保您的第 3 方也可以控制 调用您的自定义消息 dlg 而不是标准 MessageDlg 函数。那就是如果他们真的 使用它。有可能是第 3 方控制 不要使用 Delphi messagedlg 并调用 MessageBox API 直接。如果是这种情况,你可能会 最终显示消息不一致 盒子。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-11
          • 1970-01-01
          • 1970-01-01
          • 2015-05-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-04
          相关资源
          最近更新 更多