8

使用德尔福 XE2、Win64。

所以我有一个包含许多表单的大型应用程序,如果我从主表单打开帮助文件并打开一个模态窗口,然后按 F1 在模态窗口上触发上下文相关帮助,帮助文件窗口会显示正确的信息,但是在我关闭模式窗口之前,无法关闭帮助文件。如果我在模式窗口关闭之前返回应用程序,我什至无法让帮助文件再次获得焦点。

从与新版本(使用 Delphi XE2 构建)位于同一文件夹中的旧版本应用程序(使用 Delphi 6 构建)调用这个完全相同的帮助文件,当从模式窗口中按下 F1 键时,帮助文件会显示并且是反应灵敏,可以像我期望的那样关闭。

帮助文件是 .chm 类型的文件。

总结一下。

启动应用程序 通过 F1 打开帮助文件 跳转到应用程序并在应用程序中打开模式窗口 通过按 F1 从模式窗口启动帮助 帮助文件窗口无法关闭,直到我跳回我的应用程序并关闭模式窗口。

有人知道为什么会这样吗?

我搜索了互联网,没有发现任何类似的问题。

我们很难过。

干杯 TJ

- - 编辑 - -

以下是同样表现出此行为的示例两表单应用程序的一些代码。

program Project1;

uses
  Vcl.Forms,
  HTMLHelpViewer,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};

{$R *.res}

begin
  Application.Initialize;
  Application.HelpFile := 'C:\helpfile.chm';
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

这是Form1代码:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application);
  try
    Form2.ShowModal;
  finally
    Form2.Free;
  end;
end;

end.

我将两个表单上的 helpcontext 属性设置为我的帮助文件中的两个有效上下文。

运行应用程序 - F1 打开帮助文件 点击按钮以便创建 Form2 并显示 F1 以调用帮助文件 在我关闭 Form2 之前无法关闭帮助文件。

希望这可以帮助。- TJ

4

1 回答 1

9

这是一个严重的设计缺陷HtmlHelpViewer。并且很容易重现您描述的行为。做得很好,可以如此清楚地说明问题。该问题同样影响 32 位和 64 位程序。

我个人不使用HtmlHelpViewer,因为它不起作用。我为TApplication.OnHelp. 它看起来像这样:

class function THelpWindowManager.ApplicationHelp(Command: Word; 
  Data: THelpEventData; var CallHelp: Boolean): Boolean;
begin
  CallHelp := False;
  Result := True;
  //argh, WinHelp commands
  case Command of
  HELP_CONTEXT,HELP_CONTEXTPOPUP:
    HtmlHelp(GetDesktopWindow, Application.HelpFile, HH_HELP_CONTEXT, Data);
  end;
end;

把它放在一个类中并Application.OnHelp在启动时分配它:

Application.OnHelp := THelpWindowManager.ApplicationHelp;

我刚刚在简单的两个表单应用程序上对其进行了测试,它运行良好。在实际代码中,您可能希望对此进行修饰。例如,我的实际代码更复杂。它在用户设置中存储帮助窗口关闭时的位置和窗口状态。然后当再次显示时,该位置和窗口状态被恢复。这样帮助窗口就可以记住它上次在屏幕上的位置。


感谢@Sertac 在下面的评论中挖掘出细节。总之,这里是HtmlHelpViewer代码出错的地方:

  1. HH_INITIALIZE在帮助系统启动时发送命令。
  2. 文档中所述,这会将 HTML 帮助配置为在与调用应用程序相同的线程上运行,而不是在辅助线程上运行
  3. 当您调用ShowModal该调用时DisableTaskWindows,它将禁用调用线程中的窗口。
  4. 因为帮助查看器窗口是由您的应用程序的主线程创建的(由于该HH_INITIALIZE命令),所以它被禁用。

这就是为什么在 Delphi 模态表单处于活动状态时无法与预先存在的帮助窗口进行交互的原因。

于 2013-02-21T22:05:06.723 回答