【问题标题】:DELPHI 10.3 - loop while until key pressed little problemDELPHI 10.3 - 循环直到按键小问题
【发布时间】:2020-04-28 19:05:33
【问题描述】:

大家早上好, 我写了一个非常简单的应用程序,我必须等待用户按下一个键(例如 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.

【问题讨论】:

  • 操作系统是事件驱动的。不要在循环中等待,而是使用按键事件来执行任务的下一步。寻找状态机。
  • 没有跟踪,但显然问题的一部分是 WM_ACTIVATE 永远不会返回。默认窗口过程应该将焦点设置在您的表单上,由于您的循环,它永远不会被调用(或返回)。 ..由于您没有焦点,因此无法按 F2 或任何其他键。

标签: loops delphi while-loop key keypress


【解决方案1】:

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

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

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

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

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

      private
        FStarted: Boolean;
    
  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;
    
  4. 运行应用程序。

按F2后:

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

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

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

²Segoe UI是一个不错的选择,根据Microsoft Windows User Interface Guidelines。实际上,您可以将这种字体用于 form 本身;那么所有子控件都会自动继承这个字体设置。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 2021-05-17
    • 2022-01-06
    • 1970-01-01
    相关资源
    最近更新 更多