DUILIB创建不规则窗体

声明:原始方法部分已经废弃,现在有更好的办法来实现DUILIB加载PNG图片,为保持学习的渐进性,我还是保留了原始方法部分的博文与代码,大家没有必要看原始部分了,直接看新方法部分吧;

新方法

前言:上周我研究了一周如何在DUILIB中加载PNG不规则背景图,但毕竟还是新接触GDI绘图,难度还是挺大的,一直没能找到一种方法在DUILIB中不大规模修改代码的情况下,能实现PNG图片加载,正在绝望之时,一位大牛出现了,就在前一天,他发表了一篇BLOG,修改了WM_PAINT消息响应,成功的实现了加载PNG图片,具体代码我还没有看,但成功加载是一点问题都没有的,这里我就把他的代码贴出来给大家,还有这位大牛写的几个小例子,相当不错。

修改源文件及示例下载地址(不要分,仅供分享):http://download.csdn.net/detail/harvic880925/5457661

问题及解决(一定要看):

1、关键问题,在修改了WM_PAINT后,文字都变成了透明的了,很蛋疼,下面是解决方案

将下面的代码覆盖UIRender.cpp里的DrawText, 注意添加头文件和命名空间

[cpp] view plain copy
  1. #include <gdiplus.h>  
  2. #include <windowsx.h>  
  3. #include <locale.h>  
  4. using namespace Gdiplus;  
  5. #pragma comment(lib, "gdiplus.lib")  
  6.   
  7. void DrawText( HDC hDC, CPaintManagerUI* pManager,   
  8.         RECT& rc, LPCTSTR pstrText, DWORD dwTextColor, int iFont, UINT uStyle )  
  9.     {  
  10.     ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC);  
  11.     if( pstrText == NULL || pManager == NULL ) return;  
  12.     ::SetBkMode(hDC, TRANSPARENT);  
  13.     BYTE alphaValue = (dwTextColor)>>24;  
  14.   
  15.     Gdiplus::Graphics graphics(hDC);  
  16.     Font myFont(hDC,pManager->GetFont(iFont));  
  17.     RectF layoutRect(  
  18.         static_cast<REAL>(rc.left),  
  19.         static_cast<REAL>(rc.top),  
  20.         static_cast<REAL>(rc.right - rc.left),  
  21.         static_cast<REAL>(rc.bottom - rc.top));  
  22.     StringFormat format;  
  23.     StringAlignment align=StringAlignmentCenter;  
  24.     int i=uStyle%16;  
  25.     if(i==0){  //判断水平align方式  
  26.         align=StringAlignmentNear;  
  27.     }else if(i==1){  
  28.         align=StringAlignmentCenter;  
  29.     }else if(i==2){  
  30.         align=StringAlignmentFar;  
  31.     }  
  32.   
  33.     format.SetAlignment(align);  //水平方向的居左,居中,居右  
  34.     format.SetLineAlignment(StringAlignmentCenter); //垂直方向的居上,居中,和居下  
  35.       
  36.     if(uStyle & DT_END_ELLIPSIS)format.SetTrimming( StringTrimmingEllipsisCharacter );  
  37.     if(uStyle & DT_SINGLELINE) format.SetFormatFlags( StringFormatFlagsNoWrap );  
  38.     Color textcolor(dwTextColor);  
  39.   
  40.     //这里经过测试,获取到的R和B颠倒了,这里可能是GetBValue、GetRValue的提取方式与dwTextColor写入方式不同,  
  41.     //即如果用RGB写入,用COLOR的顺序方式提取是会出现颠倒现象的  
  42.     BYTE R=GetBValue(dwTextColor);  
  43.     BYTE B=GetRValue(dwTextColor);  
  44.     BYTE G=GetGValue(dwTextColor);  
  45.     SolidBrush textBrush(Color(255,R,G,B));  
  46.     graphics.DrawString(pstrText,  
  47.         -1,  
  48.         &myFont,  
  49.         layoutRect,  
  50.         &format,  
  51.         &textBrush);  
  52. }  
添加字体:

showHtml一定要设置成FALSE,不然不会进入我们的函数,字体仍然会透明,如果想使用加粗啥啥的怎么办呢,这里我们使用设置字体的办法。

先点中XXX.XML,在属性里,选择“字体管理”,然后添加字体,比如我的:

DUILIB创建不规则窗体_第1张图片

注意第一列的“Index”,然后到控件里,设置font属性,值就是要设置的字体的Index值。

如:DUILIB创建不规则窗体_第2张图片

2、创建DLG时,会出现控件与背景对不齐的现象,,有时还会出现,当鼠标移动到按钮时,对话框会从右边自动消失,

如图:DUILIB创建不规则窗体_第3张图片,红框的部分原来也是背景的一部分的,但当我移动到按钮或其它控件的时候,背景会一点点的消失掉,解决办法:

在handleMessage()里加上对WM_NCCALCSIZE和WM_NCHITTEST的响应代码!

在HandleMessage()中加上如下两句代码:

[cpp] view plain copy
  1. case WM_NCCALCSIZE:     lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;//这个一定要有,  
  2. case WM_NCHITTEST:      lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;//实现窗体大小缩放  
OnNcCalcSize和OnNcHitTest的具体实现
[cpp] view plain copy
  1. LRESULT CBaseWnd::OnNcCalcSize(UINT /*uMsg*/WPARAM /*wParam*/LPARAM /*lParam*/BOOL/*bHandled*/)  
  2. {  
  3.     return 0;  
  4. }  
  5. LRESULT CBaseWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)  
  6. {  
  7.     POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);  
  8.     ::ScreenToClient(*this, &pt);  
  9.   
  10.     RECT rcClient;  
  11.     ::GetClientRect(*this, &rcClient);  
  12.   
  13.     if( !::IsZoomed(*this) ) {  
  14.         RECT rcSizeBox = paint_manager_.GetSizeBox();  
  15.         if( pt.y < rcClient.top + rcSizeBox.top ) {  
  16.             if( pt.x < rcClient.left + rcSizeBox.left ) return HTTOPLEFT;  
  17.             if( pt.x > rcClient.right - rcSizeBox.right ) return HTTOPRIGHT;  
  18.             return HTTOP;  
  19.         }  
  20.         else if( pt.y > rcClient.bottom - rcSizeBox.bottom ) {  
  21.             if( pt.x < rcClient.left + rcSizeBox.left ) return HTBOTTOMLEFT;  
  22.             if( pt.x > rcClient.right - rcSizeBox.right ) return HTBOTTOMRIGHT;  
  23.             return HTBOTTOM;  
  24.         }  
  25.         if( pt.x < rcClient.left + rcSizeBox.left ) return HTLEFT;  
  26.         if( pt.x > rcClient.right - rcSizeBox.right ) return HTRIGHT;  
  27.     }  
  28.   
  29.     RECT rcCaption = paint_manager_.GetCaptionRect();  
  30.     if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \  
  31.         && pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) {  
  32.             CControlUI* pControl = static_cast<CControlUI*>(paint_manager_.FindControl(pt));  
  33.             if( pControl && _tcsicmp(pControl->GetClass(), _T("ButtonUI")) != 0 &&   
  34.                 _tcsicmp(pControl->GetClass(), _T("OptionUI")) != 0 /*&& 
  35.                 _tcsicmp(pControl->GetClass(), _T("TextUI")) != 0 */)  
  36.                 return HTCAPTION;  
  37.     }  
  38.   
  39.     return HTCLIENT;  
  40. }  

最后:感谢ku625的分享,现在DUILIB还处于不成熟的阶段,我们大家只有联合起来共同努力,乐于分享,才能让DUILIB更强大,我们开发起来也更容易,还有这个方法的作者建了个群:322701541,供大家交流DUILIB技术,ku625非常热心,技术也很高,很有耐心地解答了我一些问题,在此表示感谢!!!!。

此方法的原出处:http://www.yutent.com/article-68.html

原始方法

前言:在一篇中,我们讲了怎么加载XML界面,这篇文章我们将讲解怎么创建不规则窗体也就是异形窗体。我们是在上一篇工程的基础上讲解,如果大家对基本加载XML还不清楚的话,还是先看前一篇吧

先看看效果:

DUILIB创建不规则窗体_第4张图片

下面讲解实现方法:

先打开上一篇的工程,跟我一步步做;

一、准备工作

1、准备一张.png的图片(名称我们叫做bg.png),如上,注意,如果你在图片中设置不透明度为30%的话,显示出来的也将是不透明度为30%的

2、将其放在debug目录下,如图

DUILIB创建不规则窗体_第5张图片

3.用UIDesigner设计一个XML文档,按钮啥啥的我都不加了,只加一个背景,背景色为:#ffff00ff,将XML文档放在debug中的skin目录下

DUILIB创建不规则窗体_第6张图片 DUILIB创建不规则窗体_第7张图片

4、准备文件IrregularWindow.h和IrregularWindow.cpp,并将它们加载到工程中

二、写代码

1、MainFrame类中添加一个成员变量:

[cpp] view plain copy
  1. CIrregularWindow *m_pBackWnd;  

2、在CMainFrame::CMainFrame(void)函数中添加如下代码:

[cpp] view plain copy
  1. CMainFrame::CMainFrame(void)  
  2. {  
  3.     CStdString strResourcePath=CPaintManagerUI::GetInstancePath();  
  4.     CIrregularWindow::InitGDIplus();  
  5.   
  6.     m_pBackWnd = new CIrregularWindow(strResourcePath + _T("bg.png"));  
  7.   
  8.     assert(m_pBackWnd != NULL && _T("new CIrregularWindow() 失败!"));  
  9.   
  10.     if(m_pBackWnd)  
  11.     {  
  12.         HWND hBkWnd = m_pBackWnd->GetHandle();  
  13.     }  
  14. }  

意思是,在创建的时候调用CirregularWindow来初始化背景,注意这里会有一个HWND产生,也就是会有一个窗体产生,所以仅仅是这一个背景图片就会在运行的时候,在任务栏产生一个任务图标!!!!

3、在CMainFrame::OnCreate的最后添加上如下代码

[cpp] view plain copy
  1. if(m_pBackWnd)  
  2. {  
  3.     m_pBackWnd->AttachWindow(m_hWnd);//必须要让背景与当前要作为背景的窗口绑定起来  
  4. };  

一定要添加上这句,如果不添加上这句,前面搞的背景图片不会有任何效果,有兴趣大家看看这句的实现就会知道这句的作用了。这就不讲了

4、CMainFrame::HandleMessage中,添加上对WM_DESTROY的响应,在销毁窗口时,释放资源:

[cpp] view plain copy
  1. case WM_DESTROY:  
  2.     ::PostQuitMessage(0L);  
  3.     CIrregularWindow::UnInitGDIplus();  
  4.     delete m_pBackWnd;  
  5.     m_pBackWnd = NULL;  
  6.     return 0;  

5、对_tWinMain的修改

最后就是入口函数了,这里有几个地方要修改下,先看代码吧:

[cpp] view plain copy
  1. int APIENTRY _tWinMain(HINSTANCE hInstance,  
  2.                      HINSTANCE hPrevInstance,  
  3.                      LPTSTR    lpCmdLine,  
  4.                      int       nCmdShow)  
  5. {  
  6.     CPaintManagerUI::SetInstance(hInstance);//设置程序实例  
  7.     CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath()   
  8.         + _T("skin"));//实例句柄与渲染类关联,获得皮肤文件目录(加载皮肤文件在OnCreate之中)  
  9.   
  10.     HRESULT Hr = ::CoInitialize(NULL);//初始化COM库, 为加载COM库提供支持  
  11.     if( FAILED(Hr) )   
  12.         return 0;  
  13.   
  14.     CMainFrame* pMainFrame = new CMainFrame();//创建应用程序窗口类对象  
  15.     if( pMainFrame == NULL )   
  16.         return 0;  
  17.     //以背景的句柄为父窗口创建DLG,如果不这样的话,在任务栏会产生两个窗体,不信,你就把下面create的第一个参数改成NULL试试,你就懂了  
  18.     pMainFrame->Create(pMainFrame->m_pBackWnd->GetHandle(), _T("AdderCalc"), UI_WNDSTYLE_DIALOG, 0);  
  19.     //让背景图片居中  
  20.     pMainFrame->m_pBackWnd->CenterWindow();  
  21.   
  22.     pMainFrame->ShowWindow(true);//显示窗口  
  23.     CPaintManagerUI::MessageLoop();//进入消息循环  
  24.   
  25.     ::CoUninitialize();//退出程序并释放COM库  
  26.     return 0;  
  27. }  

这里更改了几个地方:

5.1:

[cpp] view plain copy
  1. pMainFrame->Create(pMainFrame->m_pBackWnd->GetHandle(), _T("AdderCalc"), UI_WNDSTYLE_DIALOG,0);  

看一个参数,以前是NULL,现在是pMainFrame->m_pBackWnd->GetHandle(),也就是将背景图片产生的窗体作为父窗口产生DLG,如果不这样在任务栏会产生两个窗体,不信,你就把下面create的第一个参数改成NULL试试,你就懂了

5.2:

[cpp] view plain copy
  1. pMainFrame->m_pBackWnd->CenterWindow();  

因为现在的主HWND是背景图片产生的窗体所以要以背景图片居中,直接pMainFrame ->CenterWindow();居中是无效的!!!

好了,到这就全部实现了,大家可以自己去添加自定义的按钮啥啥的,然后添加响应,嘿嘿

与往常一样,源码地址:http://download.csdn.net/detail/harvic880925/5374535


转载要标明出处哦:http://blog.csdn.net/harvic880925/article/details/8925650

声明:感谢金山影音漂亮的图片,该图片来源于网络,如果有任何侵权问题,请及时联系我,我会删除,谢谢!!

你可能感兴趣的:(DUILIB创建不规则窗体)