我是一个懒人,我不愿意创造一个又一个的轮子......前面刚说过StatusBar,里面可以有文字,还可以有图标(icon).本来我以为能解决我们的需求了,结果老大居然还要在上面放一个图片......
找了好长时间,没找到怎么把BitMap(或者类似)的东西变成HICON,如果能变成HICON,那么问题就解决.
没找到就另外想办法,管他三七二十一,往上画.甭管你是SendMessage发送一个HICON上去,还是怎么怎么地,到了WndProc这里,就只有WM_PAINT消息了;或者就是生硬的给HDC上面画.
先试了一下直接给HDC上面画,也比较简单,无非就是从控件的HWND获取到控件的HDC(通过GetDC(HWND)获得),然后巴拉巴拉画了上去.可是StatusBar有自己的消息处理(即窗口过程),一旦Send一个Message,StatusBar就会重绘,然后我画上去的东西就没了....杯具....
网上继续找,找到一篇文章,比较有用,"如何在 CStatusBar 窗格显示位图",来自MSDN的原文,http://support.microsoft.com/kb/149407 .其实就是重写CStatusBar的重绘函数.而我的工程不支持MFC(原谅我比较小白,不知道怎么向ATL工程里面添加MFC支持),而且如果继承那个CStatusBar,又会产生一大坨代码,而且二进制也会比较大......其实我只要截获WM_PAINT,有必要这么麻烦么??
以前看到过文章,Windows有API可以获取到窗口的窗口过程,而且还能替换,如果能那么做,不就完事了呗.查了一下,果真有API:
LONG GetWindowLong( HWND hWnd, int nIndex); LONG SetWindowLong( HWND hWnd, int nIndex, LONG dwNewLong);
而对我来讲,我无非就是先拿到StatusBar的默认窗口过程,然后换上我自定义的即可:
static WNDPROC m_OldProc=NULL; static WNDPROC m_NewProc=NULL; LRESULT MyStatusBarProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ); //初始化之后就不要管他了 m_OldProc=(WNDPROC)::GetWindowLong(m_StatusBar, GWL_WNDPROC); m_NewProc=MyStatusBarProc; ::SetWindowLong(m_StatusBar, GWL_WNDPROC, (LONG)m_NewProc);
OK,再来看MyStatusBarProc函数:
LRESULT MyStatusBarProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) { LRESULT result=::CallWindowProc(m_OldProc,hWnd,Msg,wParam,lParam); if(Msg==WM_PAINT) { PAINTSTRUCT Paint; HDC hdc=BeginPaint(hWnd,&Paint); //巴拉巴拉 EndPaint(hWnd,&Paint); } return result; }
简单几句代码就完事,我只要处理WM_PAINT消息,其他的StatusBar自己处理好了.
效果如下:
PS:
1. MFC看上去很好,实际上比较差,往往是费了功夫还不讨好.
2. WM上面的Windows程序,基本上就只能画了........杯具
3. 好像有人也把这种东西叫做子类化,我没仔细看.
其实说白了,就跟虚函数机制类似.Windows机制本身含有很多OO,或者OB的东西.
4. 据同事说,MFC里面用的也是这种东西,我不了解MFC,不晓得........