声明:原始方法部分已经废弃,现在有更好的办法来实现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
声明:感谢金山影音漂亮的图片,该图片来源于网络,如果有任何侵权问题,请及时联系我,我会删除,谢谢!!