BCB与WTL(续-VCL和WTL混用实例)

<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

自从上次我写了BCB里使用WTL的之后,有来信讨论关于BCB里使用WTL有没有价值的问题。这个问题其实和实际应用有关,每个人所在领域不同就有不同观点。

偶就不讨论这个问题了,直接用一个VCL和WTL混用的实例来说明吧:
VCL里的Hint功能是通过HintWindow来实现的,如果不通过一些手段的话它的样子是相当土的?我们这里就用2K以上系统新加入的气泡提示来代替VCL的Hint。

首先要明确一点,在VCL应用中,Application->Run已经有一个消息循环了,我们WTL里的_Moudle.Run()就不能再使用了,所以WTL里一些功能是用不上的,如:CIdleHandler, CMessageFilter等。

好,动工:
1.起手式
新建Application, 保存(假设以默认文件名保存,即Unit1.cpp,Project1.cpp这样),进入工程选项,包含路径和库路径里加入ATL,WTL所在文件夹[见BCB与WTL(一)],Conditionals里加入USING_ATLSTRICT

新建一个头文件(假设名为vclwtl.h),写上VCL,WTL都要用的头文件和一些定义:

  1. #define WINVER        0x0500
  2. #define _WIN32_WINNT    0x0501
  3. #define _WIN32_IE    0x0501
  4. #include <vcl.h>
  5. #include <atlbase.h>
  6. #include <atlapp.h>
  7. extern CAppModule _Module;
  8. #include <atlwin.h>
  9. #include <atlmisc.h>

把工程里所有的cpp文件(这里只有两个:Unit1.cpp,Project1.cpp)第一行由原来的#include <vcl.h>改成#include "vclwtl.h"

试着编译一下,应该能够成功编译。

2.定义_Module
不管这个_Module有没有用,定义还是需要地。在Project1.cpp里写上_Module的定义,变成这样子:

  1. //---------------------------------------------------------------------------
  2. #include "wtlh.h"   //上一步里改的
  3. #pragma hdrstop
  4. //---------------------------------------------------------------------------
  5. USEFORM("Unit1.cpp", Form1);
  6. //---------------------------------------------------------------------------
  7. CAppModule _Module;   // 声明
  8. WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
  9.     LPSTR lpCmdLine, int nCmdShow)
  10. {
  11.     try
  12.     {
  13.         _Module.Init(NULL,hInst); // 初始化
  14.          Application->Initialize();
  15.          Application->CreateForm(__classid(TForm1), &Form1);
  16.          Application->Run();
  17.          _Module.Term();    // 终止,没有_Module.Run()哦
  18.     }
  19.     catch (Exception &exception)
  20.     {
  21.          Application->ShowException(&exception);
  22.     }
  23.     catch (...)
  24.     {
  25.          try
  26.          {
  27.              throw Exception("");
  28.          }
  29.          catch (Exception &exception)
  30.          {
  31.              Application->ShowException(&exception);
  32.          }
  33.     }
  34.     return 0;
  35. }
  36. //---------------------------------------------------------------------------


好,现在我们就可以很嚣张地在VCL里使用WTL组件了,喔耶~~

3.引入CToolTipCtrl
因为CToolTipCtrl在atlctrls.h里,所以在Unit1.h写上#include <atlctrls.h>。在TForm1里加入成员变量CToolTipCtrl m_tip;

再编译一下,嗯?出错了?说没有ImageList_Read函数!晕,这个函数不是在commctrl.h里好好地睡着么?我找了半天也没找到怎样正确设置编译开关使其通过,算了,直接在#include <atlctrls.h>之前

加四句:

  1. WINCOMMCTRLAPI HIMAGELIST WINAPI ImageList_Read(LPSTREAM pstm);
  2. WINCOMMCTRLAPI BOOL       WINAPI ImageList_Write(HIMAGELIST himl, LPSTREAM pstm);
  3. WINCOMMCTRLAPI HRESULT WINAPI ImageList_ReadEx(DWORD dwFlags, LPSTREAM pstm, REFIID riid, PVOID* ppv);
  4. WINCOMMCTRLAPI HRESULT WINAPI ImageList_WriteEx(HIMAGELIST himl, DWORD dwFlags, LPSTREAM pstm);


如果各位路过知道有更好的办法请留言哈。

再编译试试?通过,下一步!

4.在TForm1上放一个Button1(用来演示回调方式显示ToolTip),放一个Label1(演示静态以及非TWinControl显示ToolTip的方式),在它们的Hint属性里写上一些话(演示用)。
在TForm1的构造函数里写:

  1. __fastcall TForm1::TForm1(TComponent* Owner)
  2.     : TForm(Owner)
  3. {
  4.     m_tip.Create(Handle,NULL,NULL,WS_POPUP | TTS_NOPREFIX | TTS_BALLOON);  //是气泡提示哦
  5.     m_tip.Activate(TRUE);  //激活
  6.     m_tip.AddTool(Button1->Handle);  //加入Button1,没有指定字符串就是回调方式
  7.     m_tip.AddTool(Handle, Label1->Hint.c_str(), &TRect(Label1->BoundsRect), 10); //加入Label1,注意,Label1是没有Handle的,就指定它的父窗体和它所在的位置。这里也直接指定了字符串。
  8. }


要让ToolTip可用,在WTL程序里一般是让Tooltip在PreTranslateMessage里用RelayEvent方法来更新状态,可是我们的VCL里貌似没有PreTranslateMessage功能啊?那就用TApplicationEvents来代替吧!
在TForm1上放上TApplicationEvents,处理它的OnMessage事件:

  1. void __fastcall TForm1::ApplicationEvents1Message(tagMSG &Msg,
  2.       bool &Handled)
  3. {
  4.     Handled = false;
  5.     if(Msg.hwnd == Button1->Handle || Msg.hwnd == Handle)  // AddTool里用了哪些Handle就要测试哪些,不过偷懒的话不测试也行。
  6.     {
  7.         m_tip.RelayEvent(&Msg);
  8.     }
  9. }

好,开始,编译,运行!
鼠标指向Label1,停留一下,气泡提示出来了吧?指向Button1,停一小时,还是没出来?对了,我说过是要演示回调方式的,呵呵:)
对于回调方式,在需要显示提示时ToolTips会向该控件的父控件发送code为TTN_NEEDTEXT的WM_NOTIFY消息(小提示,VCL也会把它以CN_NOTIFY的方式反射给控件本身),我们通过处理这个消息来指定要显示什么样的提示。
对于Button1,它的父控件就是TForm1,于是我们重载TForm1的WndProc函数:

  1. void __fastcall TForm1::WndProc(Messages::TMessage &Message)
  2. {
  3.     TForm::WndProc(Message);
  4.     if(Message.Msg  == WM_NOTIFY && TTN_NEEDTEXT == ((LPNMHDR)Message.LParam)->code)  //TTN_NEEDTEXT的通知消息
  5.     {
  6.         LPNMTTDISPINFO lpnmtdi = (LPNMTTDISPINFO) Message.LParam;     
  7.         HWND hwnd = GetDlgItem(Handle,lpnmtdi->hdr.idFrom);             //从ID得到HWND
  8.         TWinControl *ctrl = FindControl(hwnd);                          //从HWND得到VCL控件指针
  9.         if(ctrl)
  10.         {
  11.             lpnmtdi->lpszText = lpnmtdi->szText;                      //也可以使用别的内存,这里使用它自带的80字节(提示,默认就是这样的,所以这行可以不写)
  12.             strcpy(lpnmtdi->lpszText,(ctrl->Hint + Now().DateTimeString()).c_str());    //设置提示信息
  13.             lpnmtdi->hinst = NULL;                                    //告诉ToolTip lpnmtdi->lpszText指向的是个字符串而不是资源ID。
  14.         }
  15.     }
  16. }

再次编译运行,Button1的提示出来了吗?

5.最后
WTL里还有很多宝藏等着我们呢,大家快去挖吧:-)
提示,试试使用m_tip.SetTipBkColor来改变颜色。


<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值