Можете ли вы переопределить вызовы MessageDlg в Custom TForm/Dialog?

Я использовал код, подобный этому

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

на протяжении всего моего проекта (спасибо инструменту диалога сообщений GExperts :)), и мне было интересно, знает ли кто-нибудь способ переопределить вызов и показать мою собственную форму.

Единственный способ, которым я могу это сделать, это создать новую форму с чем-то вроде

function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
begin
  //show my own code here
end;

и поместите его в каждый из моих списков использования перед блоком диалогов, но есть ли гарантированный способ убедиться, что он использует мой код, а не код блока диалогов.
Мне не нравится идея копирования блока диалогов в локальный каталог и внесение в него изменений.

Или это все слишком много работы, и я должен просто использовать свой собственный вызов функции и заменить все MessageDlg своими собственными. (что было бы не очень весело, возможно, я слишком много использовал MessageDlg)


person Christopher Chase    schedule 20.10.2008    source источник


Ответы (5)


Кстати, вы хотите добавить его после блока Dialogs в вашем предложении Uses.

На мой взгляд, у вас есть три варианта:

  1. Добавьте свой модуль после модуля Dialogs, который имеет метод с именем MessageDlg и имеет ту же сигнатуру для создания собственной формы.
  2. Или создайте совершенно новый метод или набор методов, которые создают определенные диалоги с использованием вашей собственной формы.
  3. Выполните глобальный поиск и замену для MessageDlg с помощью DarkAxi0mMessageDlg, а затем добавьте свой модуль DarkAxi0mDialogs в предложение Uses.

Первый проблематичен, потому что вы можете пропустить модуль и все равно получить старый MessageDlg. Второй требует гораздо больше использования, но обеспечивает большую гибкость в долгосрочной перспективе. Третий, вероятно, самый простой и с наименьшими недостатками. Обязательно сделайте резервную копию перед заменой, а затем используйте инструмент сравнения (например, Beyond Compare), чтобы проверить изменения. .

person Jim McKeeth    schedule 21.10.2008
comment
Также другое использование для Sync Edit, если у вас их много в файле, просто найдите первый, выберите его в конце файла и синхронизируйте редактирование. - person skamradt; 21.10.2008
comment
GExperts project grep search хорошо помогает найти все ссылки. - person skamradt; 21.10.2008

Я бы порекомендовал вам инкапсулировать MessageDlg внутри ваших собственных процедур, таким образом, если вы измените свои процедуры, все ваши диалоги сообщений будут изменены, и вы сохраните стандарт.

Пример: создайте несколько процедур, таких как Alert(), Error(), Warning() и т. д. Если вам когда-нибудь понадобится изменить внешний вид сообщения об ошибке, вам нужно будет сделать это только в одном месте.

Когда-нибудь вы, возможно, захотите добавить изображение к своим сообщениям об ошибках, предупреждениям... что угодно, кто знает?

person Fabio Gomes    schedule 20.10.2008

Вы можете использовать такой инструмент, как TextPad, для поиска/замены всех экземпляров строки в папках и подпапках. Итак, я бы посоветовал вам заменить «MessageDlg(» на «MyMessageDlg(», чтобы вы могли настроить его по своему усмотрению. Это займет всего 5 минут.

Я думаю, что у вас возникнут проблемы, если вы создадите замену и оставите ее названной, так как в настоящее время она конфликтует с VCL.

person Argalatyr    schedule 20.10.2008
comment
Не говоря уже о путанице для программистов обслуживания! - person Blorgbeard; 21.10.2008

Вы можете взломать функцию MessageDlg и сделать так, чтобы она указывала на вашу собственную функцию MyMessageDlg (с той же сигнатурой), но я думаю, что это будет наименее безопасным из всех решений.
Плохой взлом в вместо чистого кода IMO.

Сохраните исходные коды операций MessageDlg (сгенерированные компилятором asm)
Сделайте жесткий переход к вашему коду MyMessageDlg
...тогда любой вызов MessageDlg фактически выполнит ВАШ код...
Восстановите исходный код to MessageDlg
MessageDlg теперь ведет себя как обычно

Это работает, но его следует зарезервировать для безвыходных ситуаций...

person Francesca    schedule 21.10.2008

я создал функцию MessageDlgEx на основе MessageDlg и поместил ее в один из моих файлов «библиотеки», чтобы все мои приложения могли ее использовать. моя функция позволяет вам указывать кнопки по умолчанию и отмены, давать тексты кнопок и т. д. было бы плохой практикой изменять/заменять встроенную функцию. я все еще использую встроенную функцию, но держу ее под рукой для ситуаций, когда требуется немного больше.

К вашему сведению — функция возвращает номер нажатой кнопки. первая кнопка равна 1. нажатие кнопки «Закрыть» возвращает значение 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;
person X-Ray    schedule 21.10.2008