你可以覆盖MessageDlg调用到自定义的TForm/Dialog吗?

5

我一直在使用类似这样的代码

MessageDlg('', mtWarning, [mbOK], 0);

在我的项目中(感谢GExperts消息对话框工具),我想知道是否有一种方法可以覆盖调用并显示自定义表单。我能想到的唯一方法就是创建一个类似以下代码的新表单:
function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
begin
  //show my own code here
end;

我想把它放在Dialogs单元之前的每个使用列表中,但是有没有确保它使用我的代码而不是Dialogs单元代码的方法。


我不喜欢将dialogs单元复制到本地目录并对其进行更改的想法。

或者这一切都太麻烦了,我应该只使用自己的函数调用,并将所有MessageDlg替换为我的函数调用(这并不好玩,我可能使用了太多MessageDlg)。

5个回答

5

顺便说一下,在您的 uses 子句中 Dialogs 单元后面添加它。

在我看来,您有三种选择:

  1. 在具有名为 MessageDlg 的方法且具有相同签名以创建自己的表单的 Dialogs 单元后添加自己的单元。
  2. 或创建一整��新方法或一组方法,使用自己的表单创建特定对话框。
  3. 全局搜索并用 DarkAxi0mMessageDlg 替换 MessageDlg,然后将 DarkAxi0mDialogs 单元添加到 uses 子句中,这可能是最简单且副作用最小的方法。替换之前请务必备份文件,并使用 diff 工具(如 Beyond Compare)检查更改。

第一种方法存在问题,因为您可能会错过一个单元而仍然得到旧的 MessageDlg。第二种方法需要更多的使用,但从长远来看提供更好的灵活性。第三种方法可能是最简单且副作用最少的。替换之前请确保备份文件,并使用 diff 工具(如 Beyond Compare)检查更改。


如果你的文件中有很多内容需要同步编辑,只需要找到第一个,选中它直到文件结束,然后就可以开始同步编辑了。 - skamradt
GExperts项目grep搜索功能非常出色,可以帮助找到所有的引用。 - skamradt

2

我建议你将MessageDlg封装在自己的过程中,这样如果你更改了过程,所有的消息对话框都会被更改,并且你可以保持标准。

例如:创建一些过程,如Alert()、Error()、Warning()等。如果你需要更改错误消息的外观,只需在一个地方进行即可。

总有一天你可能想在你的错误消息、警报等中添加图片,谁知道呢?


2
你可以使用类似TextPad的工具在文件夹及其子文件夹中搜索/替换字符串。因此,我建议你将"MessageDlg("替换为"MyMessageDlg(",这样你就可以随意自定义它了。应该只需花费5分钟。

我认为如果你创建一个替代品并将其命名为当前名称,则可能会与VCL发生冲突而导致问题。


更不用说对于维护程序员来说会非常困惑了! - Blorgbeard

0
我基于MessageDlg创建了一个MessageDlgEx函数,并将其放入我的“库”文件之一,以便所有应用程序都可以使用它。我的函数允许您指定默认和取消按钮,给出按钮文本等。修改/替换内置函数是不好的做法。我仍然使用内置函数,但在需要更多功能的情况下保留此函数。
顺便说一下 - 该函数返回按下的按钮编号。第一个按钮为1。按Close会导致返回值为0。按钮没有图标。
我已经使用这个函数大约5年了,它为我服务得很好。
function MessageDlgEx(Caption, Msg: string; AType: TMsgDlgType;
                      AButtons: array of string;
                      DefBtn, CanBtn: Integer; iWidth:integer=450;bCourier:boolean=false): Word;
const
  icMin=50;
  icButtonHeight=25;
  icInterspace=10;
  icButtonResultStart=100;
  icFirstButtonReturnValue=1;
var
  I, iButtonWidth, iAllButtonsWidth,
  iIconWidth,iIconHeight:Integer;
  LabelText:String;
  Frm: TForm;
  Lbl: TLabel;
  Btn: TBitBtn;
  Glyph: TImage;
  FIcon: TIcon;
  Rect:TRect;
  Caption_ca:Array[0..2000] of Char;
begin
  { Create the form.}
  Frm := TForm.Create(Application);
  Frm.BorderStyle := bsDialog;
  Frm.BorderIcons := [biSystemMenu];
  Frm.FormStyle := fsStayOnTop;
  Frm.Height := 185;
  Frm.Width := iWidth;
  Frm.Position := poScreenCenter;
  Frm.Caption := Caption;
  Frm.Font.Name:='MS Sans Serif';
  Frm.Font.Style:=[];
  Frm.Scaled:=false;

  if ResIDs[AType] <> nil then
    begin
      Glyph := TImage.Create(Frm);
      Glyph.Name := 'Image';
      Glyph.Parent := Frm;

      FIcon := TIcon.Create;
      try
        FIcon.Handle := LoadIcon(HInstance, ResIDs[AType]);
        iIconWidth:=FIcon.Width;
        iIconHeight:=FIcon.Height;
        Glyph.Picture.Graphic := FIcon;
        Glyph.BoundsRect := Bounds(icInterspace, icInterspace, FIcon.Width, FIcon.Height);
      finally
        FIcon.Free;
      end;
    end
    else
    begin
      iIconWidth:=0;
      iIconHeight:=0;
    end;

  { Loop through buttons to determine the longest caption. }
  iButtonWidth := 0;
  for I := 0 to High(AButtons) do
    iButtonWidth := Max(iButtonWidth, frm.Canvas.TextWidth(AButtons[I]));

  { Add padding for the button's caption}
  iButtonWidth := iButtonWidth + 18;

  {assert a minimum button width}
  If iButtonWidth<icMin Then
    iButtonWidth:=icMin;

  { Determine space required for all buttons}
  iAllButtonsWidth := iButtonWidth * (High(AButtons) + 1);

  { Each button has padding on each side}
  iAllButtonsWidth := iAllButtonsWidth +icInterspace*High(AButtons);

  { The form has to be at least as wide as the buttons with space on each side}
  if iAllButtonsWidth+icInterspace*2 > Frm.Width then
    Frm.Width := iAllButtonsWidth+icInterspace*2;

  if Length(Msg)>sizeof(Caption_ca) then
    SetLength(Msg,sizeof(Caption_ca));

  { Create the message control}
  Lbl := TLabel.Create(Frm);
  Lbl.AutoSize := False;
  Lbl.Left := icInterspace*2+iIconWidth;
  Lbl.Top := icInterspace;
  Lbl.Height := 200;
  Lbl.Width := Frm.ClientWidth - icInterspace*3-iIconWidth;
  Lbl.WordWrap := True;
  Lbl.Caption := Msg;
  Lbl.Parent := Frm;

  if bCourier then
    lbl.Font.Name:='Courier New';

  Rect := Lbl.ClientRect;
  LabelText:=Lbl.Caption;
  StrPCopy(Caption_ca, LabelText);

  Lbl.Height:=DrawText(Lbl.Canvas.Handle,
                       Caption_ca,
                       Length(LabelText),
                       Rect,
                       DT_CalcRect or DT_ExpandTabs or DT_WordBreak Or DT_Left);


  If Lbl.Height<iIconHeight Then
    Lbl.Height:=iIconHeight;

  { Adjust the form's height accomodating the message, padding and the buttons}
  Frm.ClientHeight := Lbl.Height + 3*icInterspace + icButtonHeight;

  { Create the pusbuttons}
  for I := 0 to High(AButtons) do
    begin
      Btn := TBitBtn.Create(Frm);
      Btn.Height := icButtonHeight;
      Btn.Width := iButtonWidth;
      Btn.Left:=((Frm.Width-iAllButtonsWidth) Div 2)+I*(iButtonWidth+icInterspace);
      Btn.Top := Frm.ClientHeight - Btn.height-icInterspace;
      Btn.Caption := AButtons[I];
      Btn.ModalResult := I + icButtonResultStart + icFirstButtonReturnValue;
      Btn.Parent := Frm;

      If I=DefBtn-1 Then
        Begin
          Frm.ActiveControl:=Btn;
          Btn.Default:=True;
        End
        Else
        Btn.Default:=False;

      If I=CanBtn-1 Then
        Btn.Cancel:=True
        Else
        Btn.Cancel:=False;
    end;

  Application.BringToFront;

  Result := Frm.ShowModal;

  {trap and convert user Close into mrNone}
  If Result=mrCancel Then
    Result:=mrNone
    Else
    If Result>icButtonResultStart Then
      Result:=Result - icButtonResultStart
      Else
      Exception.Create('Unknown MessageDlgEx result');

  Frm.Free;
end;

0

你可以劫持MessageDlg函数,并将其指向你自己的MyMessageDlg函数(具有相同的签名),但我认为这将是所有解决方案中最不安全的。
在代码整洁的情况下,这是一种糟糕的黑客方式。

保存MessageDlg的原始操作码(由编译器生成的汇编代码)
在你的MyMessageDlg代码中放置一个硬跳转
...然后任何对MessageDlg的调用实际上都会执行你的代码...
将原始代码恢复到MessageDlg
MessageDlg现在的行为与平常一样

它能够工作,但应该仅在绝望的情况下使用...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接