大家好,我编写了一个非常简单的应用程序,其中必须等待用户按下某个键(例如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.
我不想听起来刺耳,但不幸的是,您的设计存在根本缺陷。
如注释中所示,图形Windows应用程序-尤其是VCL应用程序-是事件驱动的。 (在幕后,这要归功于消息泵,但是VCL开发人员通常不需要关心这些细节。特别是,新的Delphi开发人员通常不了解底层消息泵,并且仍然可以编写高质量的GUI。如果小心的话。)
因此,例如,等待使用显式循环按下键几乎总是错误的。同样,必须调用Application.ProcessMessages
是(主要)设计缺陷的明显信号(在许多情况下(但不是在此情况下,解决方案是添加新线程))。最后,如果看似基本的任务导致您需要添加代码来解决问题(例如SetFocus
),则应始终问自己是否有更好的解决方案。
我不知道您要做什么,但是以下示例可能会有所帮助。
创建一个新的VCL应用程序。给主窗体起一个好名字,例如使用对象检查器frmMain
。在代码编辑器中,将私有字段FStarted: Boolean
添加到表单类。由于这是类中的字段,因此将对其进行初始化(因为它是Boolean
到False
)。¹
private
FStarted: Boolean;
向表单添加TLabel
控件。使用对象检查器将其名称设置为lblMainText
。将其字体设置为外观令人愉悦的²,并将其标题设置为Press F2 to begin.
在表单的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;
运行应用程序。
按F2后:
[注意,再次按F2键不会执行任何操作;您已经“启动”了系统。
显然,这个小答案不会教您编写VCL应用程序所需的全部知识。它只触及您需要知道的内容的0.1%。要了解更多信息,我强烈建议购买一本有关Delphi编程的书(特别是有关在Delphi中编写Win32应用程序的书)。
¹在Delphi中,全局变量和类成员被初始化(为0
,0.0
,False
,nil
等)。但是,局部变量永远不会初始化(除非它们属于托管类型)。
Segoe UI
,²Microsoft Windows User Interface Guidelines是一个不错的选择。实际上,您可以为form本身使用此字体;然后所有子控件将自动继承此字体设置。
³仅在表单本身具有焦点(例如,没有子控件)的情况下才有效。即使儿童控件具有焦点,也要使其正常工作,我最好的建议是使用TActionList
。它们真的很有用。