这里写目录标题
创建CDockablePane停靠窗口
步骤
- 定义一个继承自CDockablePane的类
// h文件
#pragma once
#include "afxdockablepane.h"
class CObjectWnd :
public CDockablePane
{
public:
CObjectWnd(void);
~CObjectWnd(void);
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
};
// cpp文件
#include "stdafx.h"
#include "ObjectWnd.h"
CObjectWnd::CObjectWnd(void)
{
}
CObjectWnd::~CObjectWnd(void)
{
}
BEGIN_MESSAGE_MAP(CObjectWnd, CDockablePane)
ON_WM_CREATE()
ON_WM_SIZE()
END_MESSAGE_MAP()
int CObjectWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
void CObjectWnd::OnSize(UINT nType, int cx, int cy)
{
CDockablePane::OnSize(nType, cx, cy);
}
- MainFrm.h中声明
MainFrm.h中添加头文件ObjectWnd.h,并定义CObjectWnd类的对象
include "ObjectWnd.h"
...
CObjectWnd m_wndObject;
- MainFrm.cpp中添加响应程序
BOOL CMainFrame::CreateDockingWindows() 函数中添加:
CString strObjectView("面向对象");
if (!m_wndObject.Create(strObjectView, this, CRect(0, 0, 200, 200), TRUE, 1001, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI))
{
TRACE0("未能创建“面向对象”窗口\n");
return FALSE; // 未能创建
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 函数中添加:
m_wndObject.EnableDocking(CBRS_ALIGN_ANY); //使可停靠与浮动
DockPane(&m_wndObject);
创建完成,运行即可显示。
CDockablePane停靠窗口的残影问题
停靠窗口隐藏后,鼠标移动到停靠窗口标签上显示停靠窗口,会有残影。
注意:残影问题未解决!!!!下述方法测试失败,原因正在查找中
解决方法:
① 在CObjectWnd 类中添加OnCreate和OnSize函数
② CObjectWnd::OnCreate中创建控件
CRect rectDummy;
rectDummy.SetRectEmpty();
const DWORD dwViewStyle = WS_CHILD|WS_VISIBLE|TVS_HASLINES|TVS_HASBUTTONS|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
if(!m_pointsInfo.Create(dwViewStyle,rectDummy,this,/*ID*/))
{
TRACE0(MyLoadString(IDS_CREATEPOINTINFOVIEW_ERROR));
return -;
}
③CDockable::OnSize中根据停靠窗口位置调整控件大小
if(GetSafeHwnd() == NULL)
{
return;
}
CRect rectClient;
GetClientRect(rectClient);
m_pointsInfo.SetWindowPos(NULL,rectClient.left+,rectClient.top+,rectClient.Width()-,rectClient.Height()-,SWP_NOACTIVATE|SWP_NOZORDER);
Q:隐藏停靠窗口右键菜单
A:添加WM_CONTEXTMENU消息,不实现其内容即可
afx_msg void OnContextMenu(CWnd* pWnd,CPoint point);
停靠窗口中添加控件
本文主要介绍:在MFC创建的停靠窗口中添加一些控件,浮动窗口中可以添加MFC自身的控件,也可以添加对话框。
一、创建对话框
对话框属性做以下修改:
二、窗口中添加控件
ObjectWnd.h文件:
#pragma once
#include "afxdockablepane.h"
#include "ObjectDlg.h"
#include "afxwin.h"
class CObjectWnd :
public CDockablePane
{
public:
CObjectWnd(void);
~CObjectWnd(void);
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); // 必须有
afx_msg void OnSize(UINT nType, int cx, int cy); // 在此填写改变尺寸后的重绘函数
afx_msg void OnDestroy();
void AdjustLayout();
// 定义三个控件
CEdit m_edit;
CStatic m_static;
CObjectDlg m_objectDlg; // ** 自定义的对话框类,停靠窗口内显示的对话框界面 **
};
ObjectWnd.cpp文件:
#include "stdafx.h"
#include "ObjectWnd.h"
#include "resource.h"
CObjectWnd::CObjectWnd(void)
{
}
CObjectWnd::~CObjectWnd(void)
{
}
BEGIN_MESSAGE_MAP(CObjectWnd, CDockablePane)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_DESTROY()
END_MESSAGE_MAP()
void CObjectWnd::AdjustLayout()
{
if (GetSafeHwnd () == NULL || (AfxGetMainWnd() != NULL && AfxGetMainWnd()->IsIconic())) // IsIconic()作用是判断窗口是否处于最小化状态(点击了最小化按钮之后)。
{
return;
}
CRect rectClient;
GetClientRect(rectClient); // 获得客户窗口尺寸矩形
int height = rectClient.Height()/3;
//控件在窗口中所占空间大小 动态调整控件的位置及尺寸
m_edit.SetWindowPos(this,rectClient.left,rectClient.top,rectClient.Width(),rectClient.Height()/3,SWP_NOACTIVATE | SWP_NOZORDER);
m_static.SetWindowPos(this,rectClient.left,rectClient.top+height,rectClient.Width(),rectClient.Height()/3,SWP_NOACTIVATE | SWP_NOZORDER);
m_objectDlg.SetWindowPos(this,rectClient.left,rectClient.top+height*2,rectClient.Width(),rectClient.Height()/3,SWP_NOACTIVATE | SWP_NOZORDER);
/*
SetWindowPos函数详解:
SetWindowPos(this->Handle, HWND_TOPMOST, 0, 0, 0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE );
//声明:
SetWindowPos(
hWnd: HWND; {窗口句柄}
hWndInsertAfter: HWND; {窗口的 Z 顺序}
X, Y: Integer; {位置}
cx, cy: Integer; {大小}
uFlags: UINT {选项}
): BOOL;
//hWndInsertAfter 参数可选值:
HWND_TOP = 0; {在前面}
HWND_BOTTOM = 1; {在后面}
HWND_TOPMOST = HWND(-1); {在前面, 位于任何顶部窗口的前面}
HWND_NOTOPMOST = HWND(-2); {在前面, 位于其他顶部窗口的后面}
//uFlags 参数可选值:
SWP_NOSIZE = 1; {忽略 cx、cy, 保持大小}
SWP_NOMOVE = 2; {忽略 X、Y, 不改变位置}
SWP_NOZORDER = 4; {忽略 hWndInsertAfter, 保持 Z 顺序}
SWP_NOREDRAW = 8; {不重绘}
SWP_NOACTIVATE = $10; {不激活}
不激活窗口,如果未设置标志,则窗口被激活,会被设置到其他最高级窗口或非最高级组的顶部;(设置这个属性,子窗口就不会再设置位置的时候,造成父窗口非最顶层窗口,出现闪屏)
SWP_FRAMECHANGED = $20; {强制发送 WM_NCCALCSIZE 消息, 一般只是在改变大小时才发送此消息}
SWP_SHOWWINDOW = $40; {显示窗口}
SWP_HIDEWINDOW = $80; {隐藏窗口}
SWP_NOCOPYBITS = $100; {丢弃客户区}
SWP_NOOWNERZORDER = $200; {忽略 hWndInsertAfter, 不改变 Z 序列的所有者}
SWP_NOSENDCHANGING = $400; {不发出 WM_WINDOWPOSCHANGING 消息}
SWP_DRAWFRAME = SWP_FRAMECHANGED; {画边框}
SWP_NOREPOSITION = SWP_NOOWNERZORDER;{}
SWP_DEFERERASE = $2000; {防止产生 WM_SYNCPAINT 消息}
SWP_ASYNCWINDOWPOS = $4000; {若调用进程不拥有窗口, 系统会向拥有窗口的线程发出需求}
*/
}
int CObjectWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
CRect rectDummy;
rectDummy.SetRectEmpty();
// 创建组合:
const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_BORDER | CBS_SORT | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
// 动态创建控件 控件尺寸为0
if (!m_edit.Create(dwViewStyle, rectDummy, this, 1))
{
TRACE0("未能创建CEdit控件 \n");
return -1; // 未能创建
}
// 动态创建控件
if(!m_static.Create(NULL,dwViewStyle,rectDummy,this,6))
{
TRACE0("未能创建CStatic控件\n");
return -1; // 未能创建
}
// 创建对话框窗口:
if (!m_objectDlg.Create(IDD_ObjectDlg,this)) // 创建非摸对话框
{
TRACE0("未能创建对话框窗口\n");
return -1; // 未能创建
}
m_objectDlg.ShowWindow(SW_SHOW); // 显示对话框
AdjustLayout();
//m_edit.SetWindowText(_T("CEdit控件"));
//m_static.SetWindowText(_T("CStatic控件"));
return 0;
}
void CObjectWnd::OnSize(UINT nType, int cx, int cy)
{
CDockablePane::OnSize(nType, cx, cy);
AdjustLayout(); // 自动调整控件尺寸
}
void CObjectWnd::OnDestroy()
{
CDockablePane::OnDestroy();
m_objectDlg.DestroyWindow();
// TODO: 在此处添加消息处理程序代码
}
三、添加完成,运行如下:
MFC的停靠窗口中插入对话框,在对话框中添加控件并做控件自适应
单文档程序添加了停靠窗口后,可能会在停靠窗口中添加一些控件。在这里我的做法是在对话框上添加控件并布局,然后将这个对话框插入到停靠窗口中。
步骤
-
插入对话框,在对话框中放入控件(我的为树形控件),并新建对话框类CTestDlg
-
在停靠窗口类OnCreate函数中,插入对话框
m_testDlg.Create(对话框ID,this);
m_testDlg.ShowWindow(SW_SHOW);
- 在停靠窗口类的OnSize函数中调整对话框的位置
if(GetSafeHwnd() == NULL){return;}
CRect rectClient;
GetClientRect(rectClient);
m_trdConfigDlg.SetWindowPos(NULL,rectClient.left+1,rectClient.top+1,rectClient.Width()-2,rectClient.Height()-2,SWP_NOACTIVATE|SWP_NOZORDER);
- 在对话框中调整控件的大小
if(m_trdPageTree.GetSafeHwnd() == NULL){return;}
m_trdPageTree.MoveWindow(1,1,cx-2,cy-2);
停靠窗口添加工具条
先创建工具条,设ID为IDR_Object,修改程序如下:
ObjectWnd.h修改:
#pragma once
#include "stdafx.h"
#include "afxdockablepane.h"
#include "ObjectDlg.h"
#include "afxwin.h"
//添加继承类
class CObjectToolBar : public CMFCToolBar
{
public:
virtual void OnUpdateCmdUI(CFrameWnd* /*pTarget*/, BOOL bDisableIfNoHndler)
{
CMFCToolBar::OnUpdateCmdUI((CFrameWnd*) GetOwner(), bDisableIfNoHndler);
}
virtual BOOL AllowShowOnList() const { return FALSE; }
};
class CObjectWnd :
public CDockablePane
{
public:
CObjectWnd(void);
~CObjectWnd(void);
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDestroy();
CObjectToolBar m_wndToolBar;//工具条对象
CObjectDlg m_objectDlg; //对话框类
void AdjustLayout();
};
ObjectWnd.cpp修改:
#include "stdafx.h"
#include "ObjectWnd.h"
#include "resource.h"
#include "MainFrm.h"
#include "CSDNtest.h"//添加此头文件(工程名.h)
CObjectWnd::CObjectWnd(void)
{
}
CObjectWnd::~CObjectWnd(void)
{
}
BEGIN_MESSAGE_MAP(CObjectWnd, CDockablePane)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_DESTROY()
END_MESSAGE_MAP()
void CObjectWnd::AdjustLayout()
{
if (GetSafeHwnd () == NULL || (AfxGetMainWnd() != NULL && AfxGetMainWnd()->IsIconic()))
{
return;
}
CRect rectClient;
GetClientRect(rectClient);
//设置工具条位置
int cyTlb = m_wndToolBar.CalcFixedLayout(FALSE, TRUE).cy;
m_wndToolBar.SetWindowPos(NULL, rectClient.left, rectClient.top, rectClient.Width(),cyTlb, SWP_NOACTIVATE | SWP_NOZORDER);
//控件在窗口中所占空间大小
m_objectDlg.SetWindowPos(this,rectClient.left,rectClient.top+cyTlb,rectClient.Width(),rectClient.Height()-cyTlb,SWP_NOACTIVATE | SWP_NOZORDER);
}
int CObjectWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
CRect rectDummy;
rectDummy.SetRectEmpty();
// 创建组合:
const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_BORDER | CBS_SORT | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
//创建工具条
m_wndToolBar.Create(this, AFX_DEFAULT_TOOLBAR_STYLE, IDR_Object);
m_wndToolBar.LoadToolBar(IDR_Object, 0, 0, TRUE /* 已锁定*/);
m_wndToolBar.CleanUpLockedImages();
m_wndToolBar.LoadBitmap(theApp.m_bHiColorIcons ? IDR_Object : IDR_Object, 0, 0, TRUE /* 锁定*/);
m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() | CBRS_TOOLTIPS | CBRS_FLYBY);
m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() & ~(CBRS_GRIPPER | CBRS_SIZE_DYNAMIC | CBRS_BORDER_TOP | CBRS_BORDER_BOTTOM | CBRS_BORDER_LEFT | CBRS_BORDER_RIGHT));
m_wndToolBar.SetOwner(this);
// 所有命令将通过此控件路由,而不是通过主框架路由:
m_wndToolBar.SetRouteCommandsViaFrame(FALSE);
// 创建对话框窗口:
if (!m_objectDlg.Create(IDD_ObjectDlg,this))
{
TRACE0("未能创建对话框窗口\n");
return -1; // 未能创建
}
m_objectDlg.ShowWindow(SW_SHOW);
AdjustLayout();
return 0;
}
void CObjectWnd::OnSize(UINT nType, int cx, int cy)
{
CDockablePane::OnSize(nType, cx, cy);
AdjustLayout();
}
void CObjectWnd::OnDestroy()
{
CDockablePane::OnDestroy();
m_objectDlg.DestroyWindow();
// TODO: 在此处添加消息处理程序代码
}
运行结果:
MFC系统自动生成的停靠窗格关掉后,如何重新显示?
EnableLoadDockState() 记录停靠窗状态 使能
停靠窗格关闭后,再也显示不出来了?原来,系统会默认记忆上次的状态,可以用函数来清除这个设置:
在MainFrame那个类中,CreateDocablePane之前,调用EnableLoadDockState(FALSE);即可。
EnableLoadDockState(FALSE); // 记录停靠窗状态 使能, 注意该修改会导致ribbon和dockable都状态都不记录
m_wndRibbonBar.Create(this);
m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
去掉停靠窗口右上角关闭按钮
m_ourPane.SetControlBarStyle(~AFX_CBRS_CLOSE)
禁止用户拖动可停靠窗口
m_pane.SetControlBarStyle(AFX_CBRS_RESIZE);
代码实现隐藏的窗格的再次显示
如果MFC程序不是Ribbon风格的,可以通过在View视图菜单里添加如下代码实现隐藏的窗格的再次显示:
CDockablePane::ShowPane();