MFC中创建Duilib窗口,拖动Duilib窗口,主窗口位置不变的问题

最近想学习一下MFC界面库,美化一下自己写的MFC程序,发现Duilib可以在MFC中使用,于是下载下来学习。按照里面的入门文档和网上找的一些资料终于把窗口显示出来了,但是发现拖动标题栏时只能在MFC主窗口客户区内拖动,主窗口位置不动,我的MFC主窗口是无边框无标题栏的,如果设置成有标题栏则可以拖动整个窗口,研究半天发现原因是duilib窗口是作为一个子窗口嵌在MFC的主窗口上面的,所以拖动duilib窗口对主窗口没影响。最后翻看Duilib代码里的MFCDemo项目,发现它创建duilib窗口的方法不太一样,借鉴过来,发现就没问题了,因为刚学习不久,具体的原理还没完全搞懂,在此记录一下这两种创建窗口的方法。


一般的创建窗口方法

这是入门文档中使用的方法。首先先创建 Duilib 窗口类,在MFC主窗口类中定义一个Duilib 窗口类对象,之后我们就可以创建这个Duilib窗口了。在MFC主窗口的初始化函数OnInitDialog()中添加如下代码:

m_duiFrame.Create(this->GetSafeHwnd(), _T("DUIMainFrame1"), UI_WNDSTYLE_CHILD, 0);
m_duiFrame.ShowWindow(TRUE);

一般来说要在窗口创建之前指定Duilib的实例和资源路径:

	CPaintManagerUI::SetInstance(AfxGetInstanceHandle());                    // 指定duilib的实例
	CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());    // 指定duilib资源的路径,这里指定为和exe同目录

然后还要在Duilib窗口类中处理WM_CREAT消息,Duilib中的消息处理在HandleMessage函数中:

LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
 if( uMsg == WM_CREATE ) {
 m_pm.Init(m_hWnd);
 CDialogBuilder builder;
 CControlUI* pRoot = builder.Create(_T("test1.xml"), (UINT)0, NULL, &m_pm);
 ASSERT(pRoot && "Failed to parse XML");
 m_pm.AttachDialog(pRoot);
 m_pm.AddNotifier(this);
 return 0;
 }
 else if( uMsg == WM_DESTROY ) {
 ::PostQuitMessage(0);
 }
 LRESULT lRes = 0;
 if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
 return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
 }

添加WM_CREAT消息处理的代码后,窗口就可以显示了,但是现在就会出现我遇到的拖动窗口只能在MFC主窗口内部的问题。

MFCDemo中创建方法

然后我查看了MFCDemo中是怎么解决这个问题的,发现它创建窗口并没有用Duilib的Create函数,也没有处理WM_CREATE消息。以下是它的创建创建窗口方法,也是在MFC主窗口的初始化函数OnInitDialog()中:

	// TODO: 在此添加额外的初始化代码
	this->MoveWindow(0, 0, 800, 572);
	::SetWindowLongPtr(this->GetSafeHwnd(), GWLP_USERDATA, reinterpret_cast<LPARAM>(&m_dlgWnd));
	m_dlgWnd.Subclass(this->GetSafeHwnd());
	m_dlgWnd.LoadSkin();

我去查了下Subclass函数,发现是一个子类化窗口的函数,之后LoadSkin和上面WM_CREATE消息处理的内容基本一样。也就是说唯一不同在于它将Duilib窗口子类化了,具体原理还不太清楚,总之这样Duilib窗口就和程序主窗口基本一样了。这里的SetWindowLongPtr函数在Subclass中会被调用,所以其实不写也可以,只需要Subclass函数子类化窗口,LoadSkin函数完成窗口初始化就可以了。

你可能感兴趣的:(Duilib,c++,mfc)