MFC - CDockablePane docking window learning

Create a CDockablePane docking window

step

  1. Define a class that inherits from 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. Declare in MainFrm.h
    Add the header file ObjectWnd.h in MainFrm.h, and define the object of the CObjectWnd class
include "ObjectWnd.h"

...

CObjectWnd		  m_wndObject;
  1. Add a response program in MainFrm.cpp

BOOL CMainFrame::CreateDockingWindows() function added:

	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; // 未能创建
	}

Add in int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) function:

	m_wndObject.EnableDocking(CBRS_ALIGN_ANY); //使可停靠与浮动
	DockPane(&m_wndObject);

After the creation is complete, run it and it will be displayed.

Afterimage problem of CDockablePane docking window

After the docking window is hidden, if the mouse is moved to the docking window label to display the docking window, there will be afterimages.

Note: The afterimage problem has not been resolved! ! ! ! The following method test failed, the reason is being found

Solution:
① Add OnCreate and OnSize functions in the CObjectWnd class
② Create controls in 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 -;
 }

③In CDockable::OnSize, adjust the size of the control according to the position of the docked window

 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: Hide the right-click menu of the docked window

A: Add WM_CONTEXTMENU message, just do not realize its content

afx_msg void OnContextMenu(CWnd* pWnd,CPoint point);

Add controls to the dock window

This article mainly introduces: Add some controls in the docking window created by MFC, you can add MFC's own controls in the floating window, and you can also add dialog boxes.
1. Create a dialog box
The properties of the dialog box are modified as follows:

insert image description here

2. Add the control
ObjectWnd.h file to the window:

#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 file:

#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: 在此处添加消息处理程序代码
}

3. After the addition is complete, run as follows:

insert image description here

Insert a dialog box in the docking window of MFC, add controls in the dialog box and do control adaptation

After a single-document program adds a docking window, some controls may be added to the docking window. My approach here is to add controls and layout on the dialog box, and then insert this dialog box into the docking window.

step

  1. Insert a dialog box, put controls in the dialog box (mine is a tree control), and create a new dialog box class CTestDlg

  2. In the OnCreate function of the docking window class, insert the dialog box

m_testDlg.Create(对话框ID,this);
m_testDlg.ShowWindow(SW_SHOW);
  1. Adjust the position of the dialog box in the OnSize function of the docked window class
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. Resizing controls in dialogs
if(m_trdPageTree.GetSafeHwnd() == NULL){return;}
m_trdPageTree.MoveWindow(1,1,cx-2,cy-2);

Add toolbar to docked window

Create a toolbar first, set the ID as IDR_Object, and modify the program as follows:
Modify 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 modification:

#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: 在此处添加消息处理程序代码
}

operation result:

insert image description here

After the docking pane automatically generated by the MFC system is closed, how to redisplay it?

EnableLoadDockState() Record docking window status enable

After the docking pane is closed, it doesn't show up anymore? It turns out that the system will remember the last state by default , and you can use the function to clear this setting:

In the MainFrame class, before CreateDocablePane, call EnableLoadDockState(FALSE);

EnableLoadDockState(FALSE);  // 记录停靠窗状态 使能,  注意该修改会导致ribbon和dockable都状态都不记录
m_wndRibbonBar.Create(this);
m_wndRibbonBar.LoadFromResource(IDR_RIBBON);

Remove the close button in the upper right corner of the docking window

m_ourPane.SetControlBarStyle(~AFX_CBRS_CLOSE)

Prevent users from dragging dockable windows

m_pane.SetControlBarStyle(AFX_CBRS_RESIZE);

The code realizes the display of the hidden pane again

If the MFC program is not in the Ribbon style, you can display the hidden pane again by adding the following code in the View view menu:

CDockablePane::ShowPane();

Guess you like

Origin blog.csdn.net/wu_zhiyuan/article/details/129972558