您好,Application.ProcessMessages 的作用是什么 ? (20分)

  • 主题发起人 主题发起人 LikeDFW
  • 开始时间 开始时间
L

LikeDFW

Unregistered / Unconfirmed
GUEST, unregistred user!
您好,请看如下代码:
a:// Application.ProcessMessages ; //接收系统消息
while (i < 10001) do
if b then
begin
j := 100*i ;
b: Application.ProcessMessages ; //接收系统消息
Label1.Caption := IntToStr(j) ;
c:// Application.ProcessMessages ; //接收系统消息
Sleep(100) ;
Inc(i) ;
end
else Break ;

用 Application.ProcessMessages 可以接收系统消息,但为何在上例中 ,
如果 在 b 或者 c 处用 Application.ProcessMessages ,Label1可以同步显示 ;
但如果 去掉 b,c 两处,加在 a 处 ,Label1 不能同步显示 ; 请教为何 ?

同时请教 Application.ProcessMessages的作用 ,谢谢
 
让你可以在循环过程的同时
能够响应外来的消息
 
Application.ProcessMessages从线程的消息队列中取得一条消息 并加以处理.
 
相当于vb中的 doevent;
就是在循环中,不独占进程资源,可以有机会让应用重画,和刷新,或者是接受点击.(比方说取消)
 
  当一段程序代码在执行一个很费时的操作(例如对软盘进行读写操作)时,其他控件将无法得到Windows的消息,换句话说,将一个过程被执行时,在该过程结束之前,应用程序的回调函数不会被Windows调用,也就无法响应系统消息。
  举例来说,如果在一个过程中改变了一个TLabel控件的Caption属性值,仅当该过程结束后用户才会在屏幕上看到TLabel控件被重画,如果你设计了一个拷贝文件的过程,并想在拷贝过程中不断地显示已拷贝的字节数,如果直接在拷贝操作的循环中改变要显示的字节数是不行的,用户实际上看不到这个不断变化的数字,因为当拷贝操作的过程未结束之前,其它控件根本未接收到重画消息。

  另一个极端的例子,如果你的程序要进行一个死循环,退出该死循环的条件是用户单击按钮Button2,那么你会发现在死循环执行期间,所有的控件都失效了,你的程序也就变成了一个大BUG。下面的代码示例显示了如何避免这一问题,该段程序的含义是当用户单击按钮Button1时开始执行死循环,单击Button2时退出这个死循环。

var
ExitFlag: Boolean = false;

procedure TForm1.Button1Click(Sender: TObject);
const
Busy: Boolean=false;
begin
if Busy then Exit; // 若已进入本过程则退出
Busy := true; //设立已进入本过程标志,这一句很重要
while true do begin

Application.ProcessMessages; // 让其他控件能获取消息
if ExitFlag then Break; // 若标志为真退出死循环
end;
Busy := false; // 清除已进入本过程标志
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ExitFlag := true;
end;


  上例中有两点很重要,其一是死循环中的Application.ProcessMessage,这句代码使程序的其他控件也能获取消息,如果没有这一句则程序会陷入死循环中;另一个重要的代码是在Button1Click过程开始处判断是否正在执行死循环,若是则直接退出,如果没有这个判断,则当用户重复单击Button1时可能导致代码重入,因为在过程中调用了ProcessMessage方法。
 
但我觉得它对系统关闭消息响应很迟钝,可以试一下 :
procedure TForm1.Button1Click(Sender : TObject) ;
var
j : Integer ;
begin
while (i < 10001) do
begin
j := 100*i ;
Application.ProcessMessages ; //接收系统消息
Label1.Caption := IntToStr(j) ;
Sleep(100) ;
Inc(i) ;
end ;
end;

procedure TForm1.Button2Click(Sender : TObject) ;
begin
Application.Terminate ;
end;

点击Button1运行时,再点击Button2 ,程序不能停止 ; 或者运行时你点击窗体的"X"也不能
及时关闭 ,请教为何 ? 谢谢
 
xeen :
您好 ,
"Application.ProcessMessages从线程的消息队列中取得一条消息 并加以处理."

线程有消息队列吗 ? 应该是进程 ,对吗 ?
 
Application.Terminate ;
也是通过发条WM_QUIT消息关闭程序的,是一种异步调用方式。
这样线程的消息队列没处理完是不会退出消息循环的.
 
to LikeDFW:
一个进程可能有多个线程,每个线程(除了工作线程)都有自己的消息队列。
线程根据消息的参数发给相应的窗口函数处理,也有可能线程自己处理.
 
哦,是这样, 但是 xeen 还是想请教一下, "线程的消息对列" ---- 线程有消息队列吗 /
一个 Application 应该只有一个消息队列,它有主线程管理 ,对不对 ?
 
哦,是这样 ...... Application.Run 可以为 Application 启动一个消息循环,线程
的消息循环是在线程 Create 时启动的吗 ?
 
To LikeDFW
是这样的,Application.Run 启动了主线程的消息循环,tthread.create启动了线程。
但有的线程不需要处理消息,未必有消息循环。
另外用API:
TerminateProcess(GetCurrentProcess,0);
可以无条件终止进程,但资源很可能得不到正确的释放。一般不应该用.
 
我这样想的,一个应用程序应该只有一个消息队列,有主线程管理,各个线程可以将其对VCL等等资源的使用
或者对设备的读写作为消息加入到主线程的消息队列 。 如果一个应用程序有多条消息队列,或者说有
多个消息循环,他们各做各做的处理,岂不要乱了 ?

望您指教,谢谢
 
To LikeDFW:
Delphi就是按你说的那样设计的,主线程处理各种消息。其他线程通过Synchronize
过程向主线程发消息以执行自己的过程.这是VCL的一种设计理念.但肯定不是唯一的模式.

Windows从来没有限制你在其他线程里建立消息循环,一是一个Windows窗口收到的消息只
会附加到创建这个窗口的线程的消息队列里,二是Windows还提供了一组API来同步不同
线程执行中的冲突问题.

 
谢谢您,我一知半解,还得再读读操作系统,谢谢您
 
多人接受答案了。
 
后退
顶部