MFC -CDockablePane 停靠窗口学习

本文详细介绍了如何在MFC中创建和定制CDockablePane停靠窗口,包括创建步骤、添加控件、处理残影问题、隐藏关闭按钮以及停靠窗口的显示控制。同时,文中提到了如何在停靠窗口中插入对话框,调整控件大小以适应窗口变化,并展示了如何添加工具条。
摘要由CSDN通过智能技术生成

创建CDockablePane停靠窗口

步骤

  1. 定义一个继承自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);
}
  1. MainFrm.h中声明
    MainFrm.h中添加头文件ObjectWnd.h,并定义CObjectWnd类的对象
include "ObjectWnd.h"

...

CObjectWnd		  m_wndObject;
  1. 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的停靠窗口中插入对话框,在对话框中添加控件并做控件自适应

单文档程序添加了停靠窗口后,可能会在停靠窗口中添加一些控件。在这里我的做法是在对话框上添加控件并布局,然后将这个对话框插入到停靠窗口中。

步骤

  1. 插入对话框,在对话框中放入控件(我的为树形控件),并新建对话框类CTestDlg

  2. 在停靠窗口类OnCreate函数中,插入对话框

m_testDlg.Create(对话框ID,this);
m_testDlg.ShowWindow(SW_SHOW);
  1. 在停靠窗口类的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);
  1. 在对话框中调整控件的大小
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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值