WINDOWS消息问题,高手帮忙!(100分)

  • 主题发起人 主题发起人 wk_knife
  • 开始时间 开始时间
W

wk_knife

Unregistered / Unconfirmed
GUEST, unregistred user!
我写了下面一段测试代码。单击鼠标开始SETCAPTURE,进入一个消息循环,绘制多边形。<br>双击退出循环。在消息循环中,我点击窗体的关闭按钮,想关闭窗体,结果只是结束了循环。如何才能实现关闭窗体呢?<br>unit Unit1;<br><br>interface<br><br>uses<br> &nbsp;Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br> &nbsp;Dialogs;<br><br>type<br> &nbsp;TShape=class<br> &nbsp;private<br> &nbsp; &nbsp;Pts:array of TPoint;<br> &nbsp;public<br> &nbsp; &nbsp;function AddPoint(Hint:Integer;const CoordX,CoordY:Integer):Boolean;virtual;<br> &nbsp; &nbsp;procedure Draw(Canvas:TCanvas);<br> &nbsp;end;<br><br><br> &nbsp;TForm1 = class(TForm)<br> &nbsp; &nbsp;procedure FormMouseDown(Sender: TObject; Button: TMouseButton;<br> &nbsp; &nbsp; &nbsp;Shift: TShiftState; X, Y: Integer);<br> &nbsp; &nbsp;procedure FormCreate(Sender: TObject);<br> &nbsp; &nbsp;procedure FormPaint(Sender: TObject);<br> &nbsp;private<br> &nbsp; &nbsp;{ Private declarations }<br> &nbsp; &nbsp;P:array of TShape;<br> &nbsp;public<br> &nbsp; &nbsp;{ Public declarations }<br> &nbsp; &nbsp;IsCreating:Boolean;<br> &nbsp; &nbsp;continue:Boolean;<br><br> &nbsp;end;<br><br>var<br> &nbsp;Form1: TForm1;<br><br>implementation<br><br>//uses csintf;<br><br>{$R *.dfm}<br><br>procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;<br> &nbsp;Shift: TShiftState; X, Y: Integer);<br>var<br> &nbsp;Msg:TMsg;<br> &nbsp;AShape:TShape;<br> &nbsp;K:integer;<br> &nbsp;AP:TPoint;<br>begin<br> &nbsp;if Button=mbLeft then<br> &nbsp;begin<br> &nbsp; &nbsp;if not continue then &nbsp;//如果没有开始循环<br> &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp;continue:=True;<br> &nbsp; &nbsp; &nbsp;AShape:=TShape.Create; //创建个新的多边形对象<br> &nbsp; &nbsp; &nbsp;K:=Length(P);<br> &nbsp; &nbsp; &nbsp;SetLength(P,K+1);<br> &nbsp; &nbsp; &nbsp;p[k]:=AShape; &nbsp;//加入到列表<br> &nbsp; &nbsp;end;<br> &nbsp;end;<br> &nbsp; &nbsp;SetCapture(Handle); &nbsp;<br> &nbsp; &nbsp;while Continue do &nbsp;//进入循环<br> &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp;while not PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do<br> &nbsp; &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp; &nbsp;if (GetCapture&lt;&gt;Handle) or (Msg.message = WM_CANCELMODE) &nbsp; then<br> &nbsp; &nbsp; &nbsp; &nbsp;continue:=False<br> &nbsp;else if (Msg.message &gt;= WM_MOUSEFIRST) and (Msg.message &lt;= WM_MOUSELAST) then<br> &nbsp;begin<br> &nbsp; &nbsp; &nbsp; &nbsp;if PtInRect(ClientRect,Point(LOWORD(Msg.lParam),HIWORD(msg.lParam))) then<br> &nbsp; &nbsp; &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;continue:=AShape.AddPoint(Msg.message,LOWORD(Msg.lParam),HIWORD(msg.lParam));<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;invalidate;<br> &nbsp; &nbsp; &nbsp; &nbsp;end<br> &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DispatchMessage(msg);<br> &nbsp; &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp; &nbsp;end<br> &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp;DispatchMessage(msg);<br> &nbsp; &nbsp;end; &nbsp; &nbsp;// while<br> &nbsp; &nbsp;ReleaseCapture;<br>end;<br><br>procedure TForm1.FormCreate(Sender: TObject);<br>begin<br> &nbsp;IsCreating:=False;<br> &nbsp;continue:=False;<br> &nbsp;DoubleBuffered:=True;<br>end;<br><br>procedure TForm1.FormPaint(Sender: TObject);<br>var<br> &nbsp;I: Integer;<br>begin<br> &nbsp;for I := Low(p) to High(P) do &nbsp; &nbsp;// Iterate<br> &nbsp; &nbsp;p.Draw(Canvas);<br>end;<br><br>{ TShape }<br><br>function TShape.AddPoint(Hint:Integer; const CoordX,<br> &nbsp;CoordY: Integer): Boolean;<br>var<br> &nbsp;A:Integer;<br>begin<br> &nbsp;result:=True;<br> &nbsp;if Hint=WM_LBUTTONDBLCLK then<br> &nbsp;begin<br> &nbsp; &nbsp;//codeSite.SendInteger('WM_LBUTTONDBLCLK',WM_LBUTTONDBLCLK);<br> &nbsp; &nbsp;result:=False;<br> &nbsp; &nbsp;A:=Length(pts);<br> &nbsp; &nbsp;SetLength(pts,A+1);<br> &nbsp; &nbsp;pts[A]:=Point(CoordX,CoordY);<br> &nbsp;end<br> &nbsp;else if Hint=WM_LBUTTONUP then<br> &nbsp;begin<br> &nbsp; &nbsp;//codeSite.SendInteger('WM_LBUTTONUP',WM_LBUTTONUP);<br> &nbsp; &nbsp;A:=Length(pts);<br> &nbsp; &nbsp;SetLength(pts,A+1);<br> &nbsp; &nbsp;pts[A]:=Point(CoordX,CoordY);<br> &nbsp;end;<br>end;<br><br>procedure TShape.Draw(Canvas: TCanvas);<br>begin<br> &nbsp;if Length(pts)&gt;1 then<br> &nbsp; canvas.Polygon(pts);<br>end;<br><br><br>end.
 
ExitProcess(1); 直接结束进程好了
 
请问楼上,ExitProcess(1);该写在哪个位置啊?[:D] 多想想再回答吧[:D]
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);<br>begin<br> &nbsp; Action := caFree;<br> &nbsp; Form1:= nil;<br><br>end;
 
[:(][:(][:(][:(][:(][:(][:(][:(][:(][:(]<br>混分也不能这样不负责任啊!<br>消息都被干掉了,哪里还有机会执行FormClose
 
似乎可以这样:每次获得消息的时候进行检查,如果是WM_CLOSE或者WM_QUIT就记录下来<br>并退出循环,在ReleaseCapture;之后检查获得的最后一个消息,重新向主窗体发送一遍(<br>直接Close亦可)。
 
我在循环中加了对WM_CLOSE或者WM_QUIT的处理也不行!所以才有一问。<br>while Continue do<br> &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp;while not PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do<br> &nbsp; &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp; &nbsp;if (Msg.message = WM_CLOSE) or (Msg.message = WM_QUIT) &nbsp;then<br> &nbsp; &nbsp; &nbsp; &nbsp;Application.Terminate<br> &nbsp;else if (GetCapture&lt;&gt;Handle) or (Msg.message = WM_CANCELMODE) &nbsp; then<br> &nbsp; &nbsp; &nbsp; &nbsp;continue:=False<br> &nbsp;else if (Msg.message &gt;= WM_MOUSEFIRST) and (Msg.message &lt;= WM_MOUSELAST) then<br> &nbsp;begin<br> &nbsp; &nbsp; &nbsp; &nbsp;if PtInRect(ClientRect,Point(LOWORD(Msg.lParam),HIWORD(msg.lParam))) then<br> &nbsp; &nbsp; &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;continue:=AShape.AddPoint(Msg.message,LOWORD(Msg.lParam),HIWORD(msg.lParam));<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;invalidate;<br> &nbsp; &nbsp; &nbsp; &nbsp;end<br> &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DispatchMessage(msg);<br> &nbsp; &nbsp; &nbsp; &nbsp;end;<br> &nbsp;end<br> &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp;DispatchMessage(msg);<br> &nbsp; &nbsp;end; &nbsp; &nbsp;// while<br><br>不知是哪里的问题。
 
可能是因为你接管了消息的缘故。最好是:一旦检测到,先释放消息处理权并跳出循环(<br>可以在外部用try...except结构,在循环内raise Exception,保证好使:)),然后再做其<br>它的处理——试试?
 
哈,你倒是拿异常不当异常使,这招创意很妙,我试试!
 
你可以先判断mouse的位置然后再执行你的程序,不在客户区就由默认的处理过程处理!
 
楼上的办法不行的。<br><br>我的问题是这样的,按鼠标左键,开始一个消息循环,绘制一个多边形,直到双击鼠标结束绘制,并退出消息循环。在消息循环中我会从线程的消息队列中用PEEKMESSAGE移除消息,也就是说默认的消息处理过程是处理不到这些消息的。如果如楼上说的办法,就要退出我的这个消息循环。这样我的绘制动作就不能连续了。<br><br>现在的问题估计是这样的,我现在这样处理WM_LBUTTONDOWN后,默认的消息处理过程就得不到WM_LBUTTONDOWN消息了,也就无法触发WM_CLOSE或WM_QUIT消息了,窗体就关不掉了,而我即使在处理WM_LBUTTONDOWN消息后DispatchMessage(msg),也无法产生WM_CLOSE,我估计是系统尚未来及处理WM_LBUTTONDOWN,就又被我的消息循环给移走了。所以,如何触发WM_CLOSE消息才是我要的。在标题栏上自己定位总不是个好办法吧。<br><br>如果就问题论问题,这个问题并不是那么好解决的。<br>当然我也有其他的处理办法,就这个问题,我会限制鼠标活动区域在客户区,只有绘制完成才解除限制。<br><br>另外有些人觉得这样比较累,直接为每个鼠标消息写一个处理过程不更省事么?我是基于两个方面考虑的:<br>1、一个复杂的矢量图程序有很多操作方法不一样的图元,象一般的图元的操作、带联结的图元的操作以及图元的仿射变换操作,这些操作方法如果分散写在不同的消息处理过程中,很难维护的,而且如果以后的开发者重载这些消息后,编程很容易引起错误。<br>2、以上面的方法,我的核心代码还有可能不得不暴露出来。通过上面的取得消息的循环方法,为每种操作编写一个处理类,然后只需要在WM_LBUTTONDOWN启动循环就可以了。这样我可以只发布我的窗口类的源码,而不发布处理各种图元操作的源码,而且其他用户在以后的开发中也不容易出现问题,因为他的处理方法在我的循环执行期间,很难有机会得到执行机会,除非我给他一个。
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
508
import
I
后退
顶部