声明:原始方法部分已经废弃,现在有更好的办法来实现DUILIB加载PNG图片,为保持学习的渐进性,我还是保留了原始方法部分的博文与代码,大家没有必要看原始部分了,直接看新方法部分吧;
前言:上周我研究了一周如何在DUILIB中加载PNG不规则背景图,但毕竟还是新接触GDI绘图,难度还是挺大的,一直没能找到一种方法在DUILIB中不大规模修改代码的情况下,能实现PNG图片加载,正在绝望之时,一位大牛出现了,就在前一天,他发表了一篇BLOG,修改了WM_PAINT消息响应,成功的实现了加载PNG图片,具体代码我还没有看,但成功加载是一点问题都没有的,这里我就把他的代码贴出来给大家,还有这位大牛写的几个小例子,相当不错。
修改源文件及示例下载地址(不要分,仅供分享):http://download.csdn.net/detail/harvic880925/5457661
问题及解决(一定要看):
1、关键问题,在修改了WM_PAINT后,文字都变成了透明的了,很蛋疼,下面是解决方案
将下面的代码覆盖UIRender.cpp里的DrawText, 注意添加头文件和命名空间
#include <gdiplus.h> #include <windowsx.h> #include <locale.h> using namespace Gdiplus; #pragma comment(lib, "gdiplus.lib") void DrawText( HDC hDC, CPaintManagerUI* pManager, RECT& rc, LPCTSTR pstrText, DWORD dwTextColor, int iFont, UINT uStyle ) { ASSERT(::GetObjectType(hDC)==OBJ_DC || ::GetObjectType(hDC)==OBJ_MEMDC); if( pstrText == NULL || pManager == NULL ) return; ::SetBkMode(hDC, TRANSPARENT); BYTE alphaValue = (dwTextColor)>>24; Gdiplus::Graphics graphics(hDC); Font myFont(hDC,pManager->GetFont(iFont)); RectF layoutRect( static_cast<REAL>(rc.left), static_cast<REAL>(rc.top), static_cast<REAL>(rc.right - rc.left), static_cast<REAL>(rc.bottom - rc.top)); StringFormat format; StringAlignment align=StringAlignmentCenter; int i=uStyle%16; if(i==0){ //判断水平align方式 align=StringAlignmentNear; }else if(i==1){ align=StringAlignmentCenter; }else if(i==2){ align=StringAlignmentFar; } format.SetAlignment(align); //水平方向的居左,居中,居右 format.SetLineAlignment(StringAlignmentCenter); //垂直方向的居上,居中,和居下 if(uStyle & DT_END_ELLIPSIS)format.SetTrimming( StringTrimmingEllipsisCharacter ); if(uStyle & DT_SINGLELINE) format.SetFormatFlags( StringFormatFlagsNoWrap ); Color textcolor(dwTextColor); //这里经过测试,获取到的R和B颠倒了,这里可能是GetBValue、GetRValue的提取方式与dwTextColor写入方式不同, //即如果用RGB写入,用COLOR的顺序方式提取是会出现颠倒现象的 BYTE R=GetBValue(dwTextColor); BYTE B=GetRValue(dwTextColor); BYTE G=GetGValue(dwTextColor); SolidBrush textBrush(Color(255,R,G,B)); graphics.DrawString(pstrText, -1, &myFont, layoutRect, &format, &textBrush); }添加字体:
showHtml一定要设置成FALSE,不然不会进入我们的函数,字体仍然会透明,如果想使用加粗啥啥的怎么办呢,这里我们使用设置字体的办法。
先点中XXX.XML,在属性里,选择“字体管理”,然后添加字体,比如我的:
注意第一列的“Index”,然后到控件里,设置font属性,值就是要设置的字体的Index值。
2、创建DLG时,会出现控件与背景对不齐的现象,,有时还会出现,当鼠标移动到按钮时,对话框会从右边自动消失,
如图:,红框的部分原来也是背景的一部分的,但当我移动到按钮或其它控件的时候,背景会一点点的消失掉,解决办法:
在handleMessage()里加上对WM_NCCALCSIZE和WM_NCHITTEST的响应代码!
在HandleMessage()中加上如下两句代码:
case WM_NCCALCSIZE: lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;//这个一定要有, case WM_NCHITTEST: lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;//实现窗体大小缩放OnNcCalcSize和OnNcHitTest的具体实现
LRESULT CBaseWnd::OnNcCalcSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 0; } LRESULT CBaseWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); ::ScreenToClient(*this, &pt); RECT rcClient; ::GetClientRect(*this, &rcClient); if( !::IsZoomed(*this) ) { RECT rcSizeBox = paint_manager_.GetSizeBox(); if( pt.y < rcClient.top + rcSizeBox.top ) { if( pt.x < rcClient.left + rcSizeBox.left ) return HTTOPLEFT; if( pt.x > rcClient.right - rcSizeBox.right ) return HTTOPRIGHT; return HTTOP; } else if( pt.y > rcClient.bottom - rcSizeBox.bottom ) { if( pt.x < rcClient.left + rcSizeBox.left ) return HTBOTTOMLEFT; if( pt.x > rcClient.right - rcSizeBox.right ) return HTBOTTOMRIGHT; return HTBOTTOM; } if( pt.x < rcClient.left + rcSizeBox.left ) return HTLEFT; if( pt.x > rcClient.right - rcSizeBox.right ) return HTRIGHT; } RECT rcCaption = paint_manager_.GetCaptionRect(); if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \ && pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) { CControlUI* pControl = static_cast<CControlUI*>(paint_manager_.FindControl(pt)); if( pControl && _tcsicmp(pControl->GetClass(), _T("ButtonUI")) != 0 && _tcsicmp(pControl->GetClass(), _T("OptionUI")) != 0 /*&& _tcsicmp(pControl->GetClass(), _T("TextUI")) != 0 */) return HTCAPTION; } return HTCLIENT; }
最后:感谢ku625的分享,现在DUILIB还处于不成熟的阶段,我们大家只有联合起来共同努力,乐于分享,才能让DUILIB更强大,我们开发起来也更容易,还有这个方法的作者建了个群:322701541,供大家交流DUILIB技术,ku625非常热心,技术也很高,很有耐心地解答了我一些问题,在此表示感谢!!!!。
此方法的原出处:http://www.yutent.com/article-68.html
前言:在一篇中,我们讲了怎么加载XML界面,这篇文章我们将讲解怎么创建不规则窗体也就是异形窗体。我们是在上一篇工程的基础上讲解,如果大家对基本加载XML还不清楚的话,还是先看前一篇吧
先看看效果:
下面讲解实现方法:
先打开上一篇的工程,跟我一步步做;
一、准备工作
1、准备一张.png的图片(名称我们叫做bg.png),如上,注意,如果你在图片中设置不透明度为30%的话,显示出来的也将是不透明度为30%的
2、将其放在debug目录下,如图
3.用UIDesigner设计一个XML文档,按钮啥啥的我都不加了,只加一个背景,背景色为:#ffff00ff,将XML文档放在debug中的skin目录下
4、准备文件IrregularWindow.h和IrregularWindow.cpp,并将它们加载到工程中
二、写代码
1、MainFrame类中添加一个成员变量:
CIrregularWindow *m_pBackWnd;
2、在CMainFrame::CMainFrame(void)函数中添加如下代码:
CMainFrame::CMainFrame(void) { CStdString strResourcePath=CPaintManagerUI::GetInstancePath(); CIrregularWindow::InitGDIplus(); m_pBackWnd = new CIrregularWindow(strResourcePath + _T("bg.png")); assert(m_pBackWnd != NULL && _T("new CIrregularWindow() 失败!")); if(m_pBackWnd) { HWND hBkWnd = m_pBackWnd->GetHandle(); } }
意思是,在创建的时候调用CirregularWindow来初始化背景,注意这里会有一个HWND产生,也就是会有一个窗体产生,所以仅仅是这一个背景图片就会在运行的时候,在任务栏产生一个任务图标!!!!
3、在CMainFrame::OnCreate的最后添加上如下代码
if(m_pBackWnd) { m_pBackWnd->AttachWindow(m_hWnd);//必须要让背景与当前要作为背景的窗口绑定起来 };
一定要添加上这句,如果不添加上这句,前面搞的背景图片不会有任何效果,有兴趣大家看看这句的实现就会知道这句的作用了。这就不讲了
4、CMainFrame::HandleMessage中,添加上对WM_DESTROY的响应,在销毁窗口时,释放资源:
case WM_DESTROY: ::PostQuitMessage(0L); CIrregularWindow::UnInitGDIplus(); delete m_pBackWnd; m_pBackWnd = NULL; return 0;
5、对_tWinMain的修改
最后就是入口函数了,这里有几个地方要修改下,先看代码吧:
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { CPaintManagerUI::SetInstance(hInstance);//设置程序实例 CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skin"));//实例句柄与渲染类关联,获得皮肤文件目录(加载皮肤文件在OnCreate之中) HRESULT Hr = ::CoInitialize(NULL);//初始化COM库, 为加载COM库提供支持 if( FAILED(Hr) ) return 0; CMainFrame* pMainFrame = new CMainFrame();//创建应用程序窗口类对象 if( pMainFrame == NULL ) return 0; //以背景的句柄为父窗口创建DLG,如果不这样的话,在任务栏会产生两个窗体,不信,你就把下面create的第一个参数改成NULL试试,你就懂了 pMainFrame->Create(pMainFrame->m_pBackWnd->GetHandle(), _T("AdderCalc"), UI_WNDSTYLE_DIALOG, 0); //让背景图片居中 pMainFrame->m_pBackWnd->CenterWindow(); pMainFrame->ShowWindow(true);//显示窗口 CPaintManagerUI::MessageLoop();//进入消息循环 ::CoUninitialize();//退出程序并释放COM库 return 0; }
这里更改了几个地方:
5.1:
pMainFrame->Create(pMainFrame->m_pBackWnd->GetHandle(), _T("AdderCalc"), UI_WNDSTYLE_DIALOG,0);
看一个参数,以前是NULL,现在是pMainFrame->m_pBackWnd->GetHandle(),也就是将背景图片产生的窗体作为父窗口产生DLG,如果不这样在任务栏会产生两个窗体,不信,你就把下面create的第一个参数改成NULL试试,你就懂了
5.2:
pMainFrame->m_pBackWnd->CenterWindow();
因为现在的主HWND是背景图片产生的窗体所以要以背景图片居中,直接pMainFrame ->CenterWindow();居中是无效的!!!
好了,到这就全部实现了,大家可以自己去添加自定义的按钮啥啥的,然后添加响应,嘿嘿
与往常一样,源码地址:http://download.csdn.net/detail/harvic880925/5374535
转载要标明出处哦:http://blog.csdn.net/harvic880925/article/details/8925650
声明:感谢金山影音漂亮的图片,该图片来源于网络,如果有任何侵权问题,请及时联系我,我会删除,谢谢!!