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, 注意添加头文件和命名空间

#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

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

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值