DELPHI 10.3 - 循环直到按键按下小问题

1 delphi loops key keypress while-loop

大家早上好,我写了一个非常简单的应用程序,我必须等待用户按下某个键(例如 F2)才能继续处理。按下按钮的等待周期工作正常,但我需要帮助的问题是:如果在按下按钮的等待周期中,我点击了另一个应用程序,我的应用程序失去了焦点,我无法再重新获得控制权。即使我点击应用程序的任何部分,表单的标题始终保持灰色,应用程序仍然在等待按键的压力,如果我按下所需的键,显然什么也没有发生。如何重新控制我的应用程序?我想我会在 while 循环中放置诸如 SetFocus、StayOnTop、SetForegroundWindow 等指令,以始终保持我的应用程序处于活动状态,但我无法组合任何东西...

var

  Form2: TForm2;
  mkey: word; 

implementation

{$R *.dfm} 

procedure TForm2.FormActivate(Sender: TObject);

begin

  label1.Visible:= false;

  mkey:= 0;

  keyPreview:= true;

  while mkey <> VK_F2 do begin

    label1.Visible:= true;

    label1.Caption:= datetimetostr(now);   // for example

    application.ProcessMessages;

  end;

  label1.Visible:= false;

end; 

procedure TForm2.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);

begin

  mkey:= key;

end;

end.
Run Code Online (Sandbox Code Playgroud)

And*_*and 9

我不想听起来很刺耳,但不幸的是,您的设计存在根本性缺陷。

正如评论中所指出的,图形 Windows 应用程序——尤其是 VCL 应用程序——是事件驱动的。(在幕后,这要归功于消息泵,但 VCL 开发人员通常不需要关心这些细节。特别是,新的 Delphi 开发人员通常不了解底层消息泵,但仍然可以编写高质量的 GUI应用程序,如果他们小心。)

因此,例如,使用显式循环等待按键被按下几乎总是错误的。此外,必须调用Application.ProcessMessages是(主要)设计缺陷的明显标志(在许多情况下,但不是这个,解决方案是添加一个新线程)。最后,如果一个看似基本的任务导致您需要添加代码来解决的问题(如SetFocus),您应该始终问问自己是否有更好的解决方案。

我不确切知道您要做什么,但以下示例可能会有所帮助。

  1. 创建一个新的 VCL 应用程序。给主窗体起一个好名字,比如frmMain使用对象检查器。在代码编辑器中,FStarted: Boolean向表单类添加一个私有字段。由于这是类中的一个字段,因此它已被初始化(因为它是 a Boolean, to False)。¹

      private
        FStarted: Boolean;
    
    Run Code Online (Sandbox Code Playgroud)
  2. TLabel向窗体添加控件。将其名称设置为lblMainText使用对象检查器。将其字体设置为视觉上令人愉悦的东西²,并将其标题设置为Press F2 to begin.

  3. 在表单的OnKeyDown事件处理程序中,添加以下代码³:

    procedure TfrmMain.FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      if (Key = VK_F2) and not FStarted then
      begin
        MessageBeep(MB_ICONASTERISK);
        lblMainText.Caption := 'Let''s get to work!';
        FStarted := True;
      end;
    end;
    
    Run Code Online (Sandbox Code Playgroud)
  4. 运行应用程序。

启动后立即应用程序的屏幕截图。

按F2后:

按下 F2 后应用程序的屏幕截图。

请注意,再次按 F2 不会执行任何操作;您已经“启动”了系统。

显然,这个小答案不会教您编写 VCL 应用程序所需的全部知识。它只涉及您需要了解的内容的 0.1%。要了解更多信息,我强烈建议您购买一本关于 Delphi 编程的好书(特别是关于用 Delphi 编写 Win32 应用程序)。

¹在Delphi,全局变量和类成员被初始化(至00.0Falsenil,等等)。但是,局部变量永远不会被初始化(除非它们是托管类型)。

²Segoe UI根据Microsoft Windows 用户界面指南,是一个不错的选择。实际上,您可以将这种字体用于表单本身;那么所有子控件将自动继承此字体设置。

³ 这仅在表单本身具有焦点(例如,不是子控件)时才有效。为了即使子控件具有焦点也能正常工作,我最好的建议是使用TActionList. 它们真的很有用。