关闭按钮不起作用

tjj5203 2010-04-20 03:22:06

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

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

var
Form1: TForm1;
Mark:Boolean=True;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
while Mark do
begin
Application.ProcessMessages;
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Mark:=False;
end;

end.

开始运行后,点击button1后,在不点button2前,窗体不能正常关闭,但是最小最大化都可以,这是为什么呢?
...全文
181 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
able3237 2012-01-10
  • 打赏
  • 举报
回复
并非消息不入队列,而是processmessages做了特殊判断,基本上是WM_QUIT时,只改变FTerminate
if Msg.Message <> WM_QUIT then
begin
。。。
end
else
begin
{$IF DEFINED(CLR)}
if Assigned(FOnShutDown) then FOnShutDown(self);
DoneApplication;
{$IFEND}
FTerminate := True;
end;
end;
金卯刀 2010-04-20
  • 打赏
  • 举报
回复
暈,今天咋回事,老出錯...
若再開一個窗體,程序這樣寫的話,可以正常關閉才對,因為WM_Close能被處理.....
tjj5203 2010-04-20
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 avan_lau 的回复:]

看了一下源碼,并且驗證了一下消息處理方式,前面有幾個結論要修正:
1、即使一直ProcessMessages處理隊列消息,但只要有非隊列消息產生給窗體,OS借助中斷機制,直接調用窗口過程,傳遞消息;所以WM_Close還是會被處理。查看Form.CLose,由于你的Form1是MainForm,所以會調用App.Terminate——>PostQuitMessage——>處理Applicati……
[/Quote]
好的,谢了呵呵
金卯刀 2010-04-20
  • 打赏
  • 举报
回复
看了一下源碼,并且驗證了一下消息處理方式,前面有幾個結論要修正:
1、即使一直ProcessMessages處理隊列消息,但只要有非隊列消息產生給窗體,OS借助中斷機制,直接調用窗口過程,傳遞消息;所以WM_Close還是會被處理。查看Form.CLose,由于你的Form1是MainForm,所以會調用App.Terminate——>PostQuitMessage——>處理Application.Terminated標志。倘若你在開另外一個窗體,然后這樣寫程序,就沒這么幸運可以關閉程序了。
2、HandleMessage只是在消息隊列沒有消息時,掛起線程而已,所以對你的問題也沒幫助;
tjj5203 2010-04-20
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 avan_lau 的回复:]

應該可以得出以下結論:
1、程序收到了WM_Quit,但這個消息并不是由我們的程序發出的,而是系統給的;
2、WM_Quit只是一個退出消息循環的條件,所以我們判斷App.Terminated有效果;
3、根據你原先的寫法,即使WM_QUIT收到了,但并不會結束程序——參考App.ProcessMessage;
4、循環被打破後,窗體就有機會處理WM_CLOSE了;

關于第一點,從……
[/Quote]
谢版主!
但是我感觉WM_CLOSE应该先与WM_QUIT消息啊,一般点击关闭按钮WM_CLOSE,WM_DESTORY,WM_QUIT。
但是既然WM_CLOSE是不进队消息,那么在没有处理WM_CLOSE时,系统会直接发送WM_QUIT吗
金卯刀 2010-04-20
  • 打赏
  • 举报
回复
應該可以得出以下結論:
1、程序收到了WM_Quit,但這個消息并不是由我們的程序發出的,而是系統給的;
2、WM_Quit只是一個退出消息循環的條件,所以我們判斷App.Terminated有效果;
3、根據你原先的寫法,即使WM_QUIT收到了,但并不會結束程序——參考App.ProcessMessage;
4、循環被打破後,窗體就有機會處理WM_CLOSE了;

關于第一點,從程序和VCL源碼看,并沒有顯式地PostQuitMessage或直接發送WM_QUIT,所以推斷是系統發出的
金卯刀 2010-04-20
  • 打赏
  • 举报
回复
抱歉,在OnMessage是攔截不到的WM_QUIT,因為沒有把它傳進去...
金卯刀 2010-04-20
  • 打赏
  • 举报
回复
問題確實比較奇怪

while Mark and not Application.Terminated do
Application.ProcessMessages;

若是正常流程,Application.Terminated標志被改變,應該會收到WM_quit
嘗試在onmessage攔截WM_Quit并未發現有此消息。
jdngz 2010-04-20
  • 打赏
  • 举报
回复
或者Timer
jdngz 2010-04-20
  • 打赏
  • 举报
回复
另开一个线程来做
tom2427 2010-04-20
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 avan_lau 的回复:]
procedure TForm1.Button1Click(Sender: TObject);
begin
procedure TForm1.Button1Click(Sender: TObject);
begin
while Mark do
begin
Application.HandleMessage;
end;
end;
[/Quote]
HandleMessage我试过了,窗口还是不能正常关闭。。但是我不知道为什么。。我用的是delphi 7
金卯刀 2010-04-20
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 bdmh 的回复:]

while Mark do
begin
Application.ProcessMessages;
end;
这是个死循环呀
[/Quote]
這樣寫會導致程序能處理的消息只能是隊列消息
bdmh 2010-04-20
  • 打赏
  • 举报
回复
while Mark do
begin
Application.ProcessMessages;
end;
这是个死循环呀
金卯刀 2010-04-20
  • 打赏
  • 举报
回复
點擊關閉按鈕,會產生WM_Close,而這個消息是非隊列消息;Application.ProcessMessages并不會處理到。
正是由于這段
procedure TForm1.Button1Click(Sender: TObject);
begin
while Mark do
begin
Application.ProcessMessages;
end;
end;
使得程序一直專注于處理隊列消息,沒有機會處理非隊列消息。
應該這么寫

點擊關閉按鈕,會產生WM_Close,而這個消息是非隊列消息;Application.ProcessMessages并不會處理到。
正是由于這段
procedure TForm1.Button1Click(Sender: TObject);
begin
while Mark do
begin
Application.HandleMessage;
end;
end;
tom2427 2010-04-20
  • 打赏
  • 举报
回复

while Mark and not Application.Terminated do
Application.ProcessMessages;

这样就可以了
gouxiaoyu 2010-04-20
  • 打赏
  • 举报
回复
友情UP

5,386

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧