关于Delphi XE2的FMX的一点点研究之消息篇

Delphi XE2出来了一阵子了,里面比较抢眼的东西,除了VCLStyle这个换肤的东西之外,另外最让人眼亮的应该是FMX这个东西了。万一的博客上都连载了一票的关于FMX的使用心得了。我还是没咋去关注,因为技术这个东西,天天在变,跟着他跑,俺伤不起啊!直到今天,看了一下盒子,然后群中也有人说关于FMX在Windows下面如何来发送消息的问题,说发送不了。实际上,FMX这个东西是一套跨平台机制的GUI类库,消息这个东西只是Windows下面的,所以发送消息这个说法应该不算通用。不过加以研究应该可以让Windows,Linux的综合到一个能通用的库中。

随便创建一个FMX的应用程序,上面放几个按钮什么的,然后我们跟踪一下,先看看Application这个东西,可以找到他的实现在FMX.Forms单元中,他和VCL的Application的实现不是一个东西了地。发送消息,那么首先我们应该想到几个常用的函数ProcessMessages,HandleMessage,跟进去看就直到了,然后可以发现HandleMessage的实现

function TApplication.HandleMessage: Boolean;begin  Result := Platform.HandleMessage;  if not Result then    Idle;end;

里面有一个Platform的玩意,很显然这个应该是运行时期根据不同的系统平台调用不同的实现机制,俺们是Windows平台,所以跑到他的源码目录看一下,可以发现一个很明显的名称FMX.Platform.Win,对咯,就在这个实现中了。看看TPlatformWin这个玩意的实现,我想如果熟悉Win32编程的,这个应该很明了了。不再多说,然后咱们看窗体的创建找到FMX.Forms中的CreateHandle这个东西,和上面的HandleMessage差不多的一个实现

procedure TCommonCustomForm.CreateHandle;begin  FHandle := Platform.CreateWindow(Self);  if TFmxFormState.fsRecreating in FormState then    Platform.SetWindowRect(Self, RectF(Left, Top, Left + Width, Top + Height));end;

都与platform这个平台相关了。不过话说,FMX的这个封装结构是相当的合理的,看代码让人能够一目了然,不说废话,再去看TPlatformWin的CreateWindow的实现。这个的实现和咱们VCL的实现差不多,然后我们最主要的是看看他的最后面有一个

Result := NewFmxHandle;

FHWndMap.Add(Result, Wnd);这样的实现,也就是说CreateHandle之后返回的并不是创建的窗体句柄,而是FMX管理的一个句柄索引。所以这下,咱们可直到了,FMX的Form的Handle不是这个窗口句柄而是FMX自己管理的一个索引。至于要如何获得窗口的真实句柄,在FMX.Platform.Win的最开头提供了一个函数,可实现。function FmxHandleToHWND(FmxHandle: TFmxHandle): HWND;就是这个,这个就可通过这个索引获得真实的Win32的窗口句柄。这些都说完了,那么下面我们就可以开始考究,FMX的这个消息机制了,首先发挥我们的大脑想一想,在Windows下,你所做的任何事情都要通过消息来传递的。所以说FMX这个肯定还是有消息流通的,这个是必须的。但是好多人却说,FMX的消息发送不了,为啥,呵呵这个最主要的,我前面已经说了,首先这个Win32的句柄,你换出来了没得,换出来了的话,那么你这个消息肯定是发送成功了的,否则,肯定失败了。然后我们看看最简单的一个鼠标单击消息,鼠标点窗体上的按钮会触发单击事件,那么这个按钮的鼠标消息是怎么流通的,我们先找Button的基类,一直跟下去,可以发现FMX的Control都是他自身的一套实现方式,但是没见到Win32的消息封装函数,此时俺们在发挥大脑思考一下,FMX的控件从上到下都没有再通过Win32来创建的标准方法,而且FMX的控件都没有句柄,那么我们就应该可以想到了,FMX的一整套控件的消息都是通过他的父Form来作为媒介进行传递转换而实现的,所以我们直接找到FMX的Form实现中的MouseDown过程,可以看到他的实现方式

procedure TCommonCustomForm.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);var  P: TPointF;  R: TRectF;  Obj: IControl;  SG: ISizeGrip;  i: Integer;begin  { translate coord }  FMousePos := PointF(X, Y);  FDownPos := FMousePos;  { event }  Obj := IControl(ObjectAtPoint(ClientToScreen(FMousePos)));  if (Obj <> nil) then  begin    if (IInterface(Obj).QueryInterface(ISizeGrip, SG) = 0) then      StartWindowResize    else    begin      P := Obj.ScreenToLocal(ClientToScreen(PointF(FMousePos.X, FMousePos.Y)));      Obj.MouseDown(Button, Shift, P.X, P.Y);      if (Obj.DragMode = TDragMode.dmAutomatic) then        Obj.BeginAutoDrag;    end;  end;end;

很明确他会获得鼠标按下的位置的FMX控件,然后如果获得了这个控件就调用控件的MouseDown方法,所以到这里,应该就可以很明了的知道FMX的消息是通过Form作为媒介来传递的了,那么由此说来,我们只要通过Form来转我们的消息就可以实现消息的发送了,那么这样,我们先通过消息来触发一个Button的OnClick事件。放2个按钮,然后发送消息给窗体,发送一个Down消息然后发送一个Up消息,这就构成了一个单击事件

SendMessage(FmxHandleToHWND(Handle),WM_LBUttonDown,MK_LBUTTON,MakeLong(trunc(Button1.Position.X + 3),trunc(Button1.Position.Y + 3)));  SendMessage(FmxHandleToHWND(Handle),WM_LBUttonUP,MK_LBUTTON,MakeLong(trunc(Button1.Position.X + 3),trunc(Button1.Position.Y + 3)));

然后触发一下,俺们会发现貌似并没有触发这个OnClick事件,莫非猜测失败?然后我们在找找,找到Controls的MouseUp过程

procedure TControl.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);begin  ReleaseCapture;  if Assigned(FOnMouseUp) then    FOnMouseUp(Self, Button, Shift, X, Y);  if FPressed and not(FDoubleClick) and PointInRect(PointF(X, Y), LocalRect) then  begin    FPressed := False;    Click;  end;  FPressed := False;  FDoubleClick := False;end;

里面有一个判断PointInRect(PointF(X, Y), LocalRect),可以知道是这个东西限制了只有光标在鼠标控件位置的时候才会触发OnClick事件咯。这下,可以想一个办法,用一个Timer控件在Timer的OnTimer中加上上面的消息发送代码,然后运行将鼠标移动到按钮上,等一会就会触发Button的OnClick事件了。

我想到这里,大家应该都知道如何给FMX发送消息了把!总归一句话,模拟!

FMX的消息处理过程在FMX.Platform.Win中的

function WndProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

函数!

http://www.cnblogs.com/DxSoft/archive/2011/09/27/2192795.html

时间: 2024-10-24 22:06:13

关于Delphi XE2的FMX的一点点研究之消息篇的相关文章

delphi xe2 opencv 学习

安装环境 delphi xe2 + opencv opencv 从下面的地方下载  https://github.com/Laex/Delphi-OpenCV然后按照 此网站的 说明 一项以项的 安装.重点在这里:安装opencv 的时候 代码有错误 {$ endif} 要修改为{$ ifend} 而且必须编译一次 发现一个错误 ,修改一个. 不能全部一次替换修改,因为有些不能改的(本来就正确).说不清道不明的,反正我这样搞完就 正常了. 另外一个需要注意的地方是: 32位系统好办. 如果自己的

DELPHI XE2 采用 JSON 的方式来序列化对象

DELPHI XE2 采用 JSON 的方式来序列化对象 以下代码测试通过.问题是里面的中文,在反序列化后是乱码. 1. 序列化对象为字符串,Subject 里面的中文看起来正常,仍然是中文: 2. 反序列化为对象后,Subject 里面的中文是乱码. XE2 处理 Unicode 还是有问题啊. TItemRecord = class private FID: string; FSubject: string; FADate: TDateTime; published property ID:

Delphi XE2 编译ralease版本,无法添加UAC解决方法

我今天把一个原来是Delphi2007的工程升级到了Delphi XE2,在编译ralease版本时候,发现无法添加UAC,我觉得可能是升级的原因,随后我用XE2新建了一个工程,但是在编译ralease版本时候,发现仍然无法添加UAC,但是debug版本可以加入UAC.通过多次尝试依然无法解决,最后我把工程所在目录名称修改了一下,这下子可以添加UAC了,无论哪个版本都可以添加UAC了.不知道什么原因,反正这样就可以了,如果你遇到类似问题,不妨修改一下工程目录名称试一试!

Delphi XE2 16进制转10进制《LceMeaning》

以下在编写IC卡项目时出现卡号转换错误时的解决方法,在XE2下测试正常.================================================ uses math; function HexToDec(Hex : string) : string; var i : integer; res : real; len : integer; begin len := length(Trim(Hex)); for i := 1 to len do begin case Hex[

Delphi XE2 生成的.exe 在未安装有Delphi的电脑上运行提示 “丢失 rtl160.bpl”

解决方案: XE2中加入了多平台的概念,默认的Release模式,也是带包编译,带运行时库的,所以,需要手工设置一下工程选项: 打开工程以后,Project-->Options-->左侧树列表选中C++ Linker-->右侧上方的Target选择Release configuration 下的 32-bit Windows platform-->取消 Link with Dynamic RTL 的对钩-->左侧树列表选中 Packages 下的 Runtime Packag

关于获取各种浏览器可见窗口大小的一点点研究

关于获取各种浏览器可见窗口大小的一点点研究<script>function getInfo(){var s = "";s = " 网页可见区域宽:" document.body.clientWidth;s = " 网页可见区域高:" document.body.clientHeight;s = " 网页可见区域宽:" document.body.offsetWidth " (包括边线和滚动条的宽)&quo

Delphi Xe2 后的版本如何让Delphi程序启动自动“以管理员身份运行&quot;

由于Vista以后win中加入的UAC安全机制,采用Delphi开发的程序如果不右键点击“以管理员身份运行”,则会报错. 在XE2以上的Delphi版本处理这个问题已经非常简单了. 右建点击工程,选择“Options”->“Applicaion”下,将Runtime themes项设置为“Use Custom manifest”,点击下方按钮,选择相应的Manifest文件即可. 需要注意的是:Debug和Release模式不同,要进行同样设置 如图: 至于Manifest文件,也就是一个XML

转:看看 Delphi XE2 为 VCL 提供的 14 种样式

http://www.linuxso.com/linuxbiancheng/8889.html 其实只提供了 13 个 vsf 样式文件, 还有默认的 Windows 样式, 共 14 种. 在空白窗体上添加 ListBox1 等控件, 测试代码: uses IOUtils, Vcl.Styles, vcl.Themes; procedure TForm1.FormCreate(Sender: TObject); var dir, fileName, styleName: string; beg

Delphi XE2 使用dbExpress连接MySQL数据库

MySQL安装目录下lib子目录中的libmysql.dll文件拷贝至c:/windows/system32(系统不在c盘的请转至对应目录),重新启动Delphi XE,按照上面的步骤测试连接,你会发现还是出现无法正确初始化数据库驱动的问题.最大的弯路就是使用的是安装版的MySQL.你只要使用解压版的MySQL数据库就没有问题.其实这里面真正作祟的还是libmysql.dll.只要从解压版的MySQL中提取出该版本的libmysql.dll复制到c:/windows/system32目录下就不会