How to use Delphi standard confirmation dialog but with checkbox "Don't ask me again"?
Asked Answered
P

2

7

In many confirmation dialogs it is usefull to have such option (quick wayt to disable confirmation). But i can't find how to do that. I don't want to design it myself because i need this dialog to be standard-like and don't wont to redesign with every update of Delphi. Is there simple way to use Delphi standard confirmation dialog with such checkbox ?

UPDATE2. Suggested SynTaskDialog library from Synopse project does great job (all i need and even more), i will use it in my projects. Thanks!

UPDATE. So, thank you guys for ideas. System function MessageBoxCheck is nice solution but seem to be not so stable as it should be. In general i agree that it is good idea to use latest API functions to provide users with best UI experience of modern os and use old-fashioned design for older systems. At moment i stay on simple solution (code is following), but if someone share the code with support of UI for modern OS, it will be nice.

function MsgDlgWithCB(const Msg,Title,CBMsg: string; DlgType: TMsgDlgType;
  Buttons: TMsgDlgButtons; DefaultButton: TMsgDlgBtn;
  var cbDontAskAnymore: TCheckBox): TForm;
var
  i: integer;
  b: TButton;
  y: integer;
begin
  Result := CreateMessageDialog(Msg, DlgType, Buttons, DefaultButton) ;
  Result.Position := poScreenCenter;
  cbDontAskAnymore := TCheckBox.Create(Result);
  cbDontAskAnymore.Caption := CBMsg;
  cbDontAskAnymore.Width := 130;
  y := -1;
  for i := 0 to result.ComponentCount-1 do
    if result.Components[i] is TButton then
    begin
      b := TButton(result.Components[i]);
      b.Left := b.Left + cbDontAskAnymore.Width + 16;
      Result.ClientWidth := Max(Result.ClientWidth, b.Left+b.Width+16);
      y := b.Top+b.Height-cbDontAskAnymore.Height;
    end;
  if y<0 then
    y := Result.ClientHeight - cbDontAskAnymore.height - 16;
  Result.Caption := Title;
  cbDontAskAnymore.Parent := Result;
  cbDontAskAnymore.Top := y;
  cbDontAskAnymore.Left := 8;
end;

function MessageDlgCheckbox(const Msg: string; DlgType: TMsgDlgType;
  Buttons: TMsgDlgButtons; DefaultButton: TMsgDlgBtn;
  var cbDontAskAnymore: Boolean;
  const Title: string ='Confirmation';
  const CBMsg: string = 'Don''t ask anymore'): integer;
var
  f: TForm;
  c: TCheckbox;
begin
  f := MsgDlgWithCB(Msg,Title,CBMsg,DlgType,Buttons,DefaultButton,c);
  try
    result := f.ShowModal;
    cbDontAskAnymore := c.Checked;
  finally
    f.free;
  end;
end;
Precocious answered 22/8, 2013 at 11:20 Comment(12)
The SHMessageBoxCheck function is the most Windows natural way to go.Cerate
SHMessageBoxCheck doesn't seem to be supported beyond XPChainsmoke
@David, just testing it right now. Uhm, maybe there's just missing export of it... (hence the way used in RBA's post)Cerate
Actually, SHMessageBoxCheck is kinda off-topic for this Q, but there is no way for given specsTravers
@Cerate Need to import by ordinal according to msdnChainsmoke
@David, ah, I missed to read the comments...Cerate
@Cerate I suspect this is one of the undocumented API functions that MS were compelled to document by the EU antitrust lawsuit. They make it clear that they don't want you to use it!Chainsmoke
@TLama: This function does what i need, but unfortunately there some problems reported (sometimes doesn't work with Win XP, another registry path with Win 7). I need some stable solution, so i have to use something else. At moment i stay on creating of dialog manually with CreateMessageDialog and then adding of checkbox/shifting buttons. Not so elegant solution, but i don't have something better. Thank you anyway for idea!Precocious
@Andrei, the most reliable way is creating your own dialog. Nothing is better. I don't know then, what you're expecting as answer. The answer is, make your own dialog. Delphi doesn't have something built-in for this as far as I know.Cerate
@Cerate I was expecting something like this function, it was new for me. But when i read more details i have to reject it. At the same time i found way how to customize Delphi standard dialog instead of creating of new one from the ground. It is important for me to keep dialog similar to standard one. At moment is seems to be better solution. If noone suggest something else, i will stay on this.Precocious
@David Minimum requirements for TaskDialogIndirect is Vista/2008, unfortunately it is not enough in my case, i need support of Win XP. But it is also interesting, i never used this function.Precocious
So you use task dialog on systems that support it and fall back to a custom built dialog otherwise. As per my answer. That's best for the user. Otherwise you penalise users of modern systems just to support people that still use ancient legacy XP from the dark ages. You asked for the platform native dialog, and the answer to that is task dialog.Chainsmoke
B
13

You can use our Open Source SynTaskDialog unit.

Windows provides a generic task dialog available since Vista/Seven. But there is none available with previous versions of Windows, i.e. Windows XP or 2K.

This unit (licensed under a MPL/GPL/LGPL tri-license) will use the new TaskDialog API under Vista/Seven, and emulate it with pure Delphi code and standard themed VCL components under XP or 2K. It supports Delphi 6 up to XE4, and is Win32/Win64 Unicode ready.

Here is the result under a Windows Seven 64 bit computer:

enter image description here

And here is the same dialog created from our emulated pure Delphi code:

enter image description here

Since this screenshot was made on a Win 7 machine, the styling is native for that OS. When the emulated version of the dialog runs on XP it displays in a style native to that OS.

You have your "Do not ask for this setting next time" checkbox... and potentially much more!

Ba answered 22/8, 2013 at 14:45 Comment(6)
Very nice! This looks like a good way to avoid platform limitations. Of course soon we can probably forget about XP compatibility.Larder
@Arnaud Wouldn't it be better to use an XP style dialog on XP. Putting Vista styling on XP will look very odd in my view. However, I commend you on making available such a useful piece of software.Chainsmoke
@DavidHeffernan This unit uses the XP style on XP. In fact, the above screen shot was taken under Seven, but forcing emulation. It only uses native VCL components (like TBitBtn or such), so it will look just native on every system.Ba
Perhaps you could make that clear in the answer to avoid confusion.Chainsmoke
@DavidHeffernan I modified the text in my answer.Ba
You can also set EmulateClassicStyle to True to get a more Windows Classic compatible look - see synopse.info/forum/viewtopic.php?pid=2867#p2867Teresiateresina
C
5

The system native functionality that offers such facilities is the task dialog API introduced in Vista. This provides means for you to show much more capable dialogs than the older MessageBox API.

Should you need to support XP then you will have to create your own dialog. For example by deriving from TForm and calling ShowModal. If you do this, make the form capable of building itself dynamically. Don't make one form per message that you show!

In my codebase, I have my own wrapper of the task dialog API. This detects at runtime versions of Windows that do not support task dialog and falls back on a custom built Delphi dialog.

Regarding SHMessageBoxCheck I'd be a little wary of taking a dependency on that. According to its documentation it's not supported beyond XP, and you have to import it by ordinal. I'd personally be worried that it might be dropped from a future version of Windows. That said, MS has a strong track record of doing whatever it takes to keep legacy apps working with new OS releases.

Chainsmoke answered 22/8, 2013 at 12:58 Comment(2)
I'm loving my -1 here. Any explanation?Chainsmoke
Not really. It's not in a shareable state.Chainsmoke

© 2022 - 2024 — McMap. All rights reserved.