如何使用TTaskDialog?

32
如何使用Delphi 2009及更高版本中的TTaskDialog类?官方文档没有提供有效帮助。实际上,通过使用CodeInsight或VCL源代码来检查类,您可以学到更多知识。那里没有教学解释,但至少也没有错误(好吧,只有一些)。
最近我在思考如何响应对话框中的超链接点击。确实,设置tfEnableHyperlinks标志后,您可以在对话框的文本部分中包含HTML超链接。(好吧,文档中说到该标志:“如果设置,内容、页脚和展开的文本可以包括超链接。”当然,“显然”这些链接是使用<A HTML元素实现的。)我设法自己找出要使用OnHyperLinkClick事件来响应超链接点击。但是,这个事件是一个TNotifyEvent,那么你怎么知道点击了哪个链接呢?文档对此没有任何说明,所以我不得不猜测。最终我发现对话框的URL公共属性被设置了,所以我就可以做...
procedure TmainFrm.TaskDialogHyperLinkClicked(Sender: TObject);
begin
  if Sender is TTaskDialog then
    with Sender as TTaskDialog do
      ShellExecute(0, 'open', PChar(URL), nil, nil, SW_SHOWNORMAL);
end;

官方文档中提到此属性:

URL 包含任务对话框的 URL。

现在,你必须承认,这是一个很好的解释!但情况比这更糟:文档不仅缺乏解释,还包含错误。例如,

ExpandButtonCaption:此按钮的附加信息。

那不太准确。哪个按钮?如果您显示此特定属性的帮助,则它会说

ExpandButtonCaption 包含在标题展开时要显示的其他文本。

也不好。哪个标题?适当的解释应该是

ExpandButtonCaption 是显示在按钮旁边的文本,该按钮可让用户展开对话框以显示更多信息。例如,此属性可能为“更多细节”。

无论如何,目前,我正在尝试创建一个具有两个命令链接按钮的对话框。我知道操作系统可以显示这些按钮,并且具有标题和更长的说明,但是我似乎无法使用 TTaskButton 实现它。文档不是很好

但是,与其在此处询问如何实现此特定事项,我将提出另一个问题:

有没有关于TTaskDialog类的(非官方)文档?


我找到了针对特定问题的解决方案:with TTaskDialogButtonItem(Buttons.Add) do begin Caption := 'The caption';CommandLinkHint := 'The explanation.'; end; 这并不是很明显,但它有效... - Andreas Rejbrand
1
我个人认为,直接针对Win32 Api函数进行编写会更容易,而这些函数使用起来非常简单。 - David Heffernan
@David:是的,也许我应该这样做。 - Andreas Rejbrand
如果你想支持XP,那么你需要降级到其他东西,所以你不管怎样都需要做一些工作。 - David Heffernan
4个回答

81

如果您找不到文档,则自己编写

任务对话框的Hello World

with TTaskDialog.Create(Self) do
  try
    Caption := 'My Application';
    Title := 'Hello World!';
    Text := 'I am a TTaskDialog, that is, a wrapper for the Task Dialog introduced ' +
            'in the Microsoft Windows Vista operating system. Am I not adorable?';
    CommonButtons := [tcbClose];
    Execute;
  finally
    Free;
  end;

Caption是窗口标题栏中显示的文本,Title是标题,Text是对话框的正文内容。不用说,Execute显示任务对话框,结果如下所示。(我们将在接下来的一两节中返回CommonButtons属性。)

Sample of a TTaskDialog

做一个守规矩的公民

当然,如果在 Windows XP 下运行,由于没有任务对话框 API,任务对话框将会使程序崩溃。如果禁用了视觉主题,它也无法正常工作。在任何这样的情况下,我们需要坚持使用老式的 MessageBox。因此,在实际应用中,我们需要进行如下操作:

if (Win32MajorVersion >= 6) and ThemeServices.ThemesEnabled then
  with TTaskDialog.Create(Self) do
    try
      Caption := 'My Application';
      Title := 'Hello World!';
      Text := 'I am a TTaskDialog, that is, a wrapper for the Task Dialog introduced ' +
              'in the Microsoft Windows Vista operating system. Am I not adorable?';
      CommonButtons := [tcbClose];
      Execute;
    finally
      Free;
    end
else
  MessageBox(Handle,
             'I am an ordinary MessageBox conveying the same message in order to support' +
             'older versions of the Microsoft Windows operating system (XP and below).',
             'My Application',
             MB_ICONINFORMATION or MB_OK);

在本文的其余部分,我们将假设已经支付了向后兼容性的tax,并集中于任务对话框本身。
对话框类型。模态结果 CommonButtons属性的类型为TTaskDialogCommonButtons,定义如下:
TTaskDialogCommonButton = (tcbOk, tcbYes, tcbNo, tcbCancel, tcbRetry, tcbClose);
TTaskDialogCommonButtons = set of TTaskDialogCommonButton;

该属性确定对话框中显示的按钮(如果没有手动添加按钮,我们将在稍后进行)。如果用户单击其中任何一个按钮,则相应的TModalResult值将存储在ModalResult属性中,一旦Execute返回。 MainIcon属性确定对话框中显示的图标,并且应该--当然--反映对话框的性质,就像按钮集一样。正式地说,MainIcon是一个整数,可以设置为任何值tdiNonetdiWarningtdiErrortdiInformationtdiShield
with TTaskDialog.Create(Self) do
  try
    Caption := 'My Application';
    Title := 'The Process';
    Text := 'Do you want to continue even though [...]?';
    CommonButtons := [tcbYes, tcbNo];
    MainIcon := tdiNone; // There is no tdiQuestion
    if Execute then
      if ModalResult = mrYes then
        beep;
  finally
    Free;
  end;

Sample of a TTaskDialog

以下是剩余图标类型的示例(分别为盾牌、警告和错误):

Sample of a TTaskDialog

Sample of a TTaskDialog

Sample of a TTaskDialog

最后,您应该知道可以使用DefaultButton属性在对话框中设置默认按钮。

with TTaskDialog.Create(Self) do
  try
    Caption := 'My Application';
    Title := 'The Process';
    Text := 'Do you want to continue even though [...]?';
    CommonButtons := [tcbYes, tcbNo];
    DefaultButton := tcbNo;
    MainIcon := tdiNone;
    if Execute then
      if ModalResult = mrYes then
        beep;
  finally
    Free;
  end;

Sample of a TTaskDialog

自定义按钮

您可以在任务对话框中添加自定义按钮。事实上,您可以将CommonButtons属性设置为空集,并完全依赖于自定义按钮(而且还可以有无限数量的这些按钮)。下面是一个真实案例,展示了这样一个对话框:

with TTaskDialog.Create(self) do
  try
    Title := 'Confirm Removal';
    Caption := 'Rejbrand BookBase';
    Text := Format('Are you sure that you want to remove the book file named "%s"?', [FNameOfBook]);
    CommonButtons := [];
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := 'Remove';
      ModalResult := mrYes;
    end;
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := 'Keep';
      ModalResult := mrNo;
    end;
    MainIcon := tdiNone;
    if Execute then
      if ModalResult = mrYes then
        DoDelete;
  finally
    Free;
  end

Sample of a TTaskDialog

命令链接

与传统的推按钮不同,任务对话框按钮可以是命令链接。这可以通过设置Flags中的tfUseCommandLinks标志来实现。现在您还可以设置每个按钮的CommandLinkHint属性:

with TTaskDialog.Create(self) do
  try
    Title := 'Confirm Removal';
    Caption := 'Rejbrand BookBase';
    Text := Format('Are you sure that you want to remove the book file named "%s"?', [FNameOfBook]);
    CommonButtons := [];
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := 'Remove';
      CommandLinkHint := 'Remove the book from the catalogue.';
      ModalResult := mrYes;
    end;
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := 'Keep';
      CommandLinkHint := 'Keep the book in the catalogue.';
      ModalResult := mrNo;
    end;
    Flags := [tfUseCommandLinks];
    MainIcon := tdiNone;
    if Execute then
      if ModalResult = mrYes then
        DoDelete;
  finally
    Free;
  end

Sample of a TTaskDialog

tfAllowDialogCancellation标志将恢复关闭系统菜单项(以及标题栏按钮 - 实际上,它将恢复整个系统菜单)。

Sample of a TTaskDialog

不要向最终用户抛出技术细节

您可以使用属性ExpandedTextExpandedButtonCaption来添加一段文本(前者)仅在用户单击按钮(在后者属性中的文本左侧)请求后才显示。

with TTaskDialog.Create(self) do
  try
    Title := 'Confirm Removal';
    Caption := 'Rejbrand BookBase';
    Text := Format('Are you sure that you want to remove the book file named "%s"?', [FNameOfBook]);
    CommonButtons := [];
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := 'Remove';
      CommandLinkHint := 'Remove the book from the catalogue.';
      ModalResult := mrYes;
    end;
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := 'Keep';
      CommandLinkHint := 'Keep the book in the catalogue.';
      ModalResult := mrNo;
    end;
    Flags := [tfUseCommandLinks, tfAllowDialogCancellation];
    ExpandButtonCaption := 'Technical information';
    ExpandedText := 'If you remove the book item from the catalogue, the corresponding *.book file will be removed from the file system.';
    MainIcon := tdiNone;
    if Execute then
      if ModalResult = mrYes then
        DoDelete;
  finally
    Free;
  end

下面的图像显示了用户点击按钮以显示其他详细信息后的对话框。

Sample of a TTaskDialog

如果您添加了tfExpandFooterArea标志,则额外的文本将显示在页脚中:

Sample of a TTaskDialog

无论如何,您可以通过添加tfExpandedByDefault标志使对话框以已展开的详细信息打开。

自定义图标

您可以在任务对话框中使用任何自定义图标,只需使用tfUseHiconMain标志,并在CustomMainIcon属性中指定要使用的TIcon即可。

with TTaskDialog.Create(self) do
  try
    Caption := 'About Rejbrand BookBase';
    Title := 'Rejbrand BookBase';
    CommonButtons := [tcbClose];
    Text := 'File Version: ' + GetFileVer(Application.ExeName) + #13#10#13#10'Copyright © 2011 Andreas Rejbrand'#13#10#13#10'http://english.rejbrand.se';
    Flags := [tfUseHiconMain, tfAllowDialogCancellation];
    CustomMainIcon := Application.Icon;
    Execute;
  finally
    Free;
  end

Sample of a TTaskDialog

超链接

您甚至可以在对话框中(在

和中)使用类似HTML的超链接,只需添加tfEnableHyperlinks标志即可:

with TTaskDialog.Create(self) do
  try
    Caption := 'About Rejbrand BookBase';
    Title := 'Rejbrand BookBase';
    CommonButtons := [tcbClose];
    Text := 'File Version: ' + GetFileVer(Application.ExeName) + #13#10#13#10'Copyright © 2011 Andreas Rejbrand'#13#10#13#10'<a href="http://english.rejbrand.se">http://english.rejbrand.se</a>';
    Flags := [tfUseHiconMain, tfAllowDialogCancellation, tfEnableHyperlinks];
    CustomMainIcon := Application.Icon;
    Execute;
  finally
    Free;
  end

Sample of a TTaskDialog

注意,当您单击链接时,不会发生任何事情。 链接的操作必须手动实现,这当然是一件好事。 要做到这一点,请响应 OnHyperlinkClicked 事件,该事件是一个 TNotifyEvent。 链接的 URL(即 a 元素的 href)存储在 TTaskDialogURL 公共属性中:

procedure TForm1.TaskDialogHyperLinkClicked(Sender: TObject);
begin
  if Sender is TTaskDialog then
    with Sender as TTaskDialog do
      ShellExecute(0, 'open', PChar(URL), nil, nil, SW_SHOWNORMAL);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  with TTaskDialog.Create(self) do
    try
      Caption := 'About Rejbrand BookBase';
      Title := 'Rejbrand BookBase';
      CommonButtons := [tcbClose];
      Text := 'File Version: ' + GetFileVer(Application.ExeName) + #13#10#13#10'Copyright © 2011 Andreas Rejbrand'#13#10#13#10'<a href="http://english.rejbrand.se">http://english.rejbrand.se</a>';
      Flags := [tfUseHiconMain, tfAllowDialogCancellation, tfEnableHyperlinks];
      OnHyperlinkClicked := TaskDialogHyperlinkClicked;
      CustomMainIcon := Application.Icon;
      Execute;
    finally
      Free;
    end
end;

页脚

您可以使用FooterFooterIcon属性创建一个页脚。 icon属性接受与MainIcon属性相同的值。

with TTaskDialog.Create(self) do
  try
    Caption := 'My Application';
    Title := 'A Question';
    Text := 'This is a really tough one...';
    CommonButtons := [tcbYes, tcbNo];
    MainIcon := tdiNone;
    FooterText := 'If you do this, then ...';
    FooterIcon := tdiWarning;
    Execute;
  finally
    Free;
  end

Sample of a TTaskDialog

使用tfUseHiconFooter标志和CustomFooterIcon属性,您可以像选择自己的主图标一样,在页脚中使用任何自定义图标。

复选框

使用VerificationText字符串属性,您可以在任务对话框的页脚中添加复选框。复选框的标题是该属性。
with TTaskDialog.Create(self) do
  try
    Caption := 'My Application';
    Title := 'A Question';
    Text := 'This is a really tough one...';
    CommonButtons := [tcbYes, tcbNo];
    MainIcon := tdiNone;
    VerificationText := 'Remember my choice';
    Execute;
  finally
    Free;
  end

Sample of a TTaskDialog

您可以通过指定tfVerificationFlagChecked标志来使复选框最初被选中。不幸的是,在TTaskDialog的VCL实现中存在一个bug(?), 当在Execute返回时包括此标志时,它并未反映复选框的最终状态。因此,为了跟踪复选框,应用程序需要记住初始状态,并在每次OnVerificationClicked事件响应中切换内部标志,该事件在对话框的模态期间每次复选框状态更改时触发。

单选按钮

单选按钮可以以类似于添加自定义推按钮(或命令链接按钮)的方式实现:

with TTaskDialog.Create(self) do
  try
    Caption := 'My Application';
    Title := 'A Question';
    Text := 'This is a really tough one...';
    CommonButtons := [tcbOk, tcbCancel];
    MainIcon := tdiNone;
    with RadioButtons.Add do
      Caption := 'This is one option';
    with RadioButtons.Add do
      Caption := 'This is another option';
    with RadioButtons.Add do
      Caption := 'This is a third option';
    if Execute then
      if ModalResult = mrOk then
        ShowMessage(Format('You chose %d.', [RadioButton.Index]));
  finally
    Free;
  end

Sample of a TTaskDialog


5
好的写作。额外付出的努力加一分。 - Chris Thornton
1
@Leonardo:也许你现在已经自己发现了,但是有 SynTaskDialog(http://blog.synopse.info/post/2011/03/05/Open-Source-SynTaskDialog-unit-for-XP%2CVista%2CSeven)可用。它的仿真并不涵盖Microsoft任务对话框可以完成的所有功能,而且它看起来有点粗糙,但它是有效的。 - Uli Gerhardt
1
与此同时,复选框标志“tfVerificationFlagChecked”的问题似乎已经解决。我正在使用Delphi XE3,它运行良好。 - Tupel
6
Embarcadero 应该使用你的代码并奖励你一个免费许可证。 - Gabriel
3
这是SO上最好的答案。我想宣布您为StackOverflow的荣誉公民。 - Gabriel
显示剩余14条评论

7

4

是的,我知道这个包装器,但我更喜欢不使用第三方组件来完成任务。 - Andreas Rejbrand
说实话,我认为任务对话框在XP上看起来不好。它们看起来不协调。我的建议是,在Vista/7上使用任务对话框,在XP上使用老式的MessageBox,就像我在http://specials.rejbrand.se/TTaskDialog中所做的那样。 - Andreas Rejbrand
然而,这并不会在XP上破坏您的应用程序。即使Andreas认为这不是一个坏主意。其他专业软件社区对这种限制并不太看好。如果您的软件只是玩具,那就没问题了。对您来说,外观更重要还是完全的功能破坏更重要? - Warren P
@Warren P:我的所有应用程序在Windows XP上都能完美运行。我总是在Vista/7上使用TTaskDialog,而在XP上使用MessageBox。如果你认为这会在XP上“破坏”应用程序,那么这就是你(和Embarcadero的?)的观点。 - Andreas Rejbrand
TMS任务对话框在使用VCL样式时存在一些丑陋的问题。 - user1580348

1

这是我的简短文档:

  1. 除非你不想让你的应用程序在XP上工作,否则不要使用它。

  2. 建议改进delphi doc wiki内容,就像其他人一样,但请注意短语“注意:任务对话框需要Vista或Windows 7”。那是“不要使用它!”的代码。基本上,有人想要完全支持新的Windows Vista对话框,而完成的方式是编写仅调用对话框API的包装器代码。由于没有为您提供回退功能,因此在XP上运行时会出现问题。


2
我总是测试操作系统版本和视觉主题的可用性(是的,如果没有启用Aero,则TTaskDialog在Vista/7上无法工作),如果可能的话,使用TTaskDialog,如果不行则使用普通的MessageBox,就像http://specials.rejbrand.se/TTaskDialog中所示。 TTaskDialog美妙的视觉风格使得这些额外的工作都值得。 (但说实话,我真的感觉像“今天谁还在使用XP?”) - Andreas Rejbrand
我认为责怪 Embarcadero 不能让 TTaskDialog 在 XP 上工作是不明智的,因为 TTaskDialog 只是一个操作系统 API 的包装器,这在 Vista 中是新的。是的,也许如果 TTaskDialog 在 XP 上(或没有视觉主题)进行了一些自定义处理,可以稍微简化开发人员的生活(这种简化如果他们仅使用本机 OS API 就不会存在),但我认为您不应要求包装器这样做。 - Andreas Rejbrand
声明:我在 Embarcadero 工作。但我个人仍然不喜欢那些不能在所有常见的 Windows 版本上工作的组件。如果你想编写你的应用程序,在 XP 上无法工作,没问题。但要记住,stackoverflow 不仅关乎你和你的问题,它也涉及到后来者将会阅读这些信息。所以尽管踩我吧。但其他人可能会出现,并需要了解这一点。 - Warren P
1
@Warren,看看Andreas的写作吧。他的例子展示了如何使它在XP上很好地回退。 - Chris Thornton
幸运的是,XP现在已经成为历史。 - mjn
显示剩余3条评论

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