Generic dialog with custom captions for buttons
Asked Answered
I

3

12

I know this issue have been up since before (ex. Best way to show customized message dialogs), but I still don't find what I want.

I started like this:

class function TAttracsForm.MessageDlg(const aMsg: string; aDlgType: TMsgDlgType; Buttons: TMsgDlgButtons; aCaptions: array of String; aDefault: TMsgDlgBtn): TModalResult;
var
  vDlg: TForm;
  i: Integer; 
begin
  if aButtons.Count = aCaptions.Count then
  begin
    vDlg := CreateMessageDialog(aMsg, aDlgType, Buttons);
    try
      for i := 0 aCaptions.Count - 1 do
        TButton(vDlg.FindComponent(Buttons[i].Caption)).Caption := aCaptions[i]; 

      vDlg.Position := poDefaultPosOnly;
      Result := vDlg.ShowModal;
    finally
      vDlg.Free;
    end;
  end;
end;

And the call would look like:

if (MessageDlg('Really quit application ?', mtWarning, 
       [mbNo, mbCancel, mbYes], {'No save', 'Cancel', 'Save'}) = mrYes) then

But the above code of course don't compile. I don't know how to get one item of an set in the loop and how to get the total count of it in the beginning.

Isocrates answered 24/3, 2011 at 10:37 Comment(6)
Maybe you can use TTaskDialog or one of the pre-Vista capable emulations.Pun
+1 I agree that the Vista task dialog is the way to go when it is available.Endemic
My application run only on XP and Server 2003 R2 so I cannot use TTaskDialog.Isocrates
@Roland: There are emulations, e.g. JSDialog, one from TMS, SynTaskDialogPun
Inofficial TTaskDialog documentationPsychogenic
@Andreas: <OT>You could set HTML anchors in your inofficial docu and then directly link to, say, "Custom Buttons"</OT>Pun
A
22

you can use this code:

function MyMessageDlg(CONST Msg: string; DlgTypt: TmsgDlgType; button: TMsgDlgButtons;
  Caption: ARRAY OF string; dlgcaption: string): Integer;
var
  aMsgdlg: TForm;
  i: Integer;
  Dlgbutton: Tbutton;
  Captionindex: Integer;
begin
  aMsgdlg := createMessageDialog(Msg, DlgTypt, button);
  aMsgdlg.Caption := dlgcaption;
  aMsgdlg.BiDiMode := bdRightToLeft;
  Captionindex := 0;
  for i := 0 to aMsgdlg.componentcount - 1 Do
  begin
    if (aMsgdlg.components[i] is Tbutton) then
    Begin
      Dlgbutton := Tbutton(aMsgdlg.components[i]);
      if Captionindex <= High(Caption) then
        Dlgbutton.Caption := Caption[Captionindex];
      inc(Captionindex);
    end;
  end;
  Result := aMsgdlg.Showmodal;
end;

For example:

MyMessageDlg('Hello World!', mtInformation, [mbYes, mbNo],
      ['Yessss','Noooo'], 'New MessageDlg Box'):
Antebi answered 4/9, 2013 at 17:24 Comment(5)
Work perfectly but in example must use , and not ; for dividing parameters and you can check it with normal MessageDlg results. So use it as this way: if MyMessageDlg('Hello World!', mtInformation, [mbYes, mbNo], ['Yessss','Noooo'], 'New MessageDlg Box') = mrYes then Begin .... EndResnick
@Holmes For a solution with Firemonkey have a look at this answer.Protect
Unfortunately, this does not work in Lazarus 1.8.0. The custom caption does not affect the actual button caption, ist just 'yes' and 'no.'Birdiebirdlike
Why set it to bdRightToLeft? It ends up destroying the text.Resemblance
@JerryDodge Because it was supposed to run for Right to Left languages like Persian ;) For Left to Right languages, you don't need.Antebi
E
8

How about something like this:

type
  TButtonInfo = record
    MsgDlgBtn: TMsgDlgBtn;
    Caption: string;
  end;

function ButtonInfo(MsgDlgBtn: TMsgDlgBtn; const Caption: string): TButtonInfo;
begin
  Result.MsgDlgBtn := MsgDlgBtn;
  Result.Caption := Caption;
end;

const
  ModalResults: array[TMsgDlgBtn] of Integer = (
    mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, mrNoToAll,
    mrYesToAll, 0, mrClose);

function FindDialogButton(Form: TForm; MsgDlgBtn: TMsgDlgBtn): TButton;
var
  i: Integer;
  Component: TComponent;
begin
  for i := 0 to Form.ComponentCount-1 do begin
    Component := Form.Components[i];
    if Component is TButton then begin
      if TButton(Component).ModalResult=ModalResults[MsgDlgBtn] then begin
        Result := TButton(Component);
        exit;
      end;
    end;
  end;
  Result := nil;
end;

function MessageDlg(
  const aMsg: string;
  aDlgType: TMsgDlgType;
  const Buttons: array of TButtonInfo;
  aDefault: TMsgDlgBtn
): TModalResult;
var
  i: Integer;
  MsgDlgButtons: TMsgDlgButtons;
  vDlg: TForm;
begin
  MsgDlgButtons := [];
  for i := low(Buttons) to high(Buttons) do begin
    Assert(not (Buttons[i].MsgDlgBtn in MsgDlgButtons));//assert uniqueness
    Include(MsgDlgButtons, Buttons[i].MsgDlgBtn);
  end;
  vDlg := CreateMessageDialog(aMsg, aDlgType, MsgDlgButtons, aDefault);
  try
    for i := low(Buttons) to high(Buttons) do begin
      FindDialogButton(vDlg, Buttons[i].MsgDlgBtn).Caption := Buttons[i].Caption;
    end;
    vDlg.Position := poDefaultPosOnly;
    Result := vDlg.ShowModal;
  finally
    vDlg.Free;
  end;
end;

procedure Test;
begin
  MessageDlg(
    'Really quit application ?',
    mtWarning,
    [ButtonInfo(mbNo, 'Do&n''t save'), ButtonInfo(mbCancel, '&Cancel'), ButtonInfo(mbYes,'&Save')],
    mbYes
  );
end;

enter image description here

Endemic answered 24/3, 2011 at 10:47 Comment(18)
Why not? Is it because I used accelerator keys perhaps? Also, "This doesn't work" isn't a very good error report..... ;-)Endemic
@David - that's the error message most of our users report! LOLOutcaste
I think you might not want FindComponent(Buttons[i].Caption). It is pretty unlikely that the unmodified dialog has a control named 'Do&nt'' save'.Psychogenic
It's a bit interesting that you get upvotes even though your code doesn't work! Clearly, people aren't actually trying the code before upvoting! Still, your code is beautiful, and deserves a lot of upvotes as soon as the bug is fixed.Psychogenic
@Andreas @Roland Code works now!! Pretty hacky, but there you go. Would be quite easy to roll your own Task Dialog type form.Endemic
@Andreas Thanks! Not sure I'd say beautiful though!!Endemic
@David: Interesting, your solution is identical to the one I just wrote, that is, using a conversion array between buttons and modal results.Psychogenic
@Andreas It's funny, I saw all the other issues with the code, but assumed the FindComponent stuff was fine since I never do stuff like that anyway!Endemic
David I tried the code and it doesn't work because of the reason Andreas said. FindComponent(Buttons[i].Caption) may be wrong. But I think the problem is solved anyway even if it isn't exactly as I want it. And the upvote is just for a good try for you David... :)Isocrates
@Roland The code works perfectly. You are probably running the original version. I edited it yesterday and now it works. As you can see above, there is no call to FindComponent. This is your answer.Endemic
@ShahramBanazadeh What do you mean?Endemic
@DavidHeffernan I can not see routine that sets default (selected ) button passed by last parameter(adefault) .not implemented ?Beria
@Shahram How it is set? Again I don't know what you mean. Why don't you read the code and see how the parameter is used?Endemic
@DavidHeffernan Because it is not used. I was wondering if I am missing some thing. aDefault: TMsgDlgBtn is not used in body.Beria
I see. I've fixed it now.Endemic
(Posted for [stackoverflow.com/users/6227080/nervouz](Nervouz) who can't comment himself.) Nice code @DavidHeffernan! It`s work for me. I can't anwer on your post. There are some way to make the length of buttons "customized" or "Justified"? Thank you!Pun
@computer the question is about delphiEndemic
I wrote many custom dialog functions for personal use, but your approach was beautiful, thanks @DavidHeffernanSeparate
N
3

I write this code: (I am from Croatia, so the texts are in Croatian)

function MojDijalog(const Msg, Capt: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
  DefaultButton: TMsgDlgBtn): TModalResult;
var
  dlg : TForm;
begin
  dlg := CreateMessageDialog(Msg, DlgType, Buttons, DefaultButton) ;
  with dlg do begin
     Caption := Capt;
     FormStyle := fsStayOnTop;
     ( FindComponent( 'OK' ) as TButton ).Caption := 'U redu' ;
     ( FindComponent( 'Cancel' ) as TButton ).Caption := 'Odustani' ;
     ( FindComponent( 'Yes' ) as TButton ).Caption := 'Da' ;
     ( FindComponent( 'No' ) as TButton ).Caption := 'Ne' ;
      ( FindComponent( 'Help' ) as TButton ).Caption := 'Pomoć' ;
     ( FindComponent( 'Close' ) as TButton ).Caption := 'Zatvori' ;
     ( FindComponent( 'Ignore' ) as TButton ).Caption := 'Zanemari' ;
     ( FindComponent( 'Retry' ) as TButton ).Caption := 'Pokušaj ponovo' ;
     ( FindComponent( 'Abort' ) as TButton ).Caption := 'Prekini' ;
     ( FindComponent( 'All' ) as TButton ).Caption := 'Sve' ;
  end;
  Result := dlg.ShowModal;
end;

Example of use :

if MojDijalog('Obrisati zapis ?','Upit za brisanje',mtConfirmation,mbYesNo,mbNo) = mrNo then
    begin
         Abort;
    end;
Newfashioned answered 18/11, 2019 at 15:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.