您的位置:首页 > 其它

MFC浮动窗口的创建

2017-10-11 13:59 232 查看
首先创建MFC类  基类为CDockablePane  以下分别定义动态悬浮窗口h文件和C文件 

#pragma once

#include "PARAM_VIEW.h" 

// Cdockvedio

class Cdockvedio : public CDockablePane

{
DECLARE_DYNAMIC(Cdockvedio)

public:
Cdockvedio();
virtual ~Cdockvedio();
virtual BOOL CanBeClosed() const;    // 重载基类 隐藏关闭按钮  

protected:
CListBox _listBox;

// CPARAM_VIEW   paraviewDialog;

protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
DECLARE_MESSAGE_MAP()

};

///////////////////////////////////////////////////////////////////////////////

// Cdockvedio.cpp : 实现文件

// 

#include "Cdockvedio.h"

#include "stdafx.h"

// Cdockvedio

IMPLEMENT_DYNAMIC(Cdockvedio, CDockablePane)

Cdockvedio::Cdockvedio()

{

}

Cdockvedio::~Cdockvedio()

{

}

int Cdockvedio::OnCreate(LPCREATESTRUCT lpCreateStruct)

{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
// 在这儿创建控件
if (!_listBox.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, IDD_Param_FORMVIEW))
{
TRACE0("创建listbox失败");
return -1;
}
return 0;

}

void Cdockvedio::OnSize(UINT nType, int cx, int cy)

{
CDockablePane::OnSize(nType, cx, cy);
// 这儿添加代码
if (GetSafeHwnd() == NULL)
{
return;
}
if (_listBox.GetSafeHwnd() != NULL)
{
CRect rectClient;
GetClientRect(rectClient);
_listBox.SetWindowPos(NULL, rectClient.left, rectClient.top, rectClient.Width(), rectClient.Height(), SWP_NOACTIVATE | SWP_NOZORDER);
}

}

BOOL Cdockvedio::CanBeClosed() const     

{
return FALSE;

}

BEGIN_MESSAGE_MAP(Cdockvedio, CDockablePane)
ON_WM_CREATE()
ON_WM_SIZE()

END_MESSAGE_MAP()

具体的步骤如下 :

1. 创建悬浮窗口类

每一个悬浮窗口都是一个CDockablePane的派生类的对象, 因此要为每一个悬浮窗口创建一个新类

1.1 添加类

通过菜单Project->Add Class...或者在类视图中工程名字处右键选择Add->Class...添加类

选择MFC Class, 点Add按钮进入下一步

Class name处写入新类的名字, 这里用CDock, 选择Base class为CDockablePane

按Finish按钮, 添加类完成.

1.2 添加消息处理函数

一般至少要处理两个消息, 一个是WM_CREATE, 一个是WM_SIZE, 具体步骤为:

(1) 头文件中添加函数声明(函数名及参数不可写错)

protected:

 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

 afx_msg void OnSize(UINT nType, int cx, int cy);

(2) cpp文件中添加消息映射

BEGIN_MESSAGE_MAP(CDock, CDockablePane)

 ON_WM_CREATE()

 ON_WM_SIZE()

END_MESSAGE_MAP()

这里BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏都是自动生成的, 只需要添加中间两行代码即可

(3) 添加函数实现部分

int CDock::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

 if (CDockablePane::OnCreate(lpCreateStruct) == -1)

  return -1;

 // 在这儿创建控件

 return 0;

}

void CDock::OnSize(UINT nType, int cx, int cy)

{

 CDockablePane::OnSize(nType, cx, cy);

 // 这儿添加代码

}

1.3 添加控件

现在创建的CDock类中由于没有任何控件, 因此如果现在创建该类的对象并显示, 该区域中由于全是垃圾数据, 故可能该窗口显示时为花屏. 如果程序运行期间出现类似花屏的问题, 大概会有几种可能性: 1. 没有创建控件 2. 已创建控件, 但控件位置不对或未覆盖整个的dockablePane 3. 控件虽然占据整个区域, 但不能自动刷新

这里以添加一个listBox为例:

(1) 在类的头文件中添加控件对象, 代码为:

protected:

 CListBox _listBox;

(2) 在OnCreate()中添加创建控件窗口的代码:

这里必须要注意, 需要先调用基类的函数OnCrea
4000
te()

int CDock1::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

 if (CDockablePane::OnCreate(lpCreateStruct) == -1)

  return -1;

 // 在这儿创建控件

 // nID为该控件的ID, 可以自行设置, 如果对ID不感兴趣, 也可以选择传递0让系统做处理

 if (!_listBox.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, nID))

 {

  TRACE0("创建listbox失败");

  return -1;

 }

 return 0;

}

(3) 在OnSize中设置各个控件的位置

这里要注意的是, 需要将控件布满整个窗口. 这里只有一个listBox, 故可以直接用listBox覆盖窗口.

同理, 必须要先调用基类函数CDockablePane::OnSize(nType, cx, cy)

void CDock::OnSize(UINT nType, int cx, int cy)

{

 CDockablePane::OnSize(nType, cx, cy);

 // 这儿添加代码

 if (GetSafeHwnd() == NULL)

 {

  return;

 }

 if (_listBox.GetSafeHwnd() != NULL)

 {

  CRect rectClient;

  GetClientRect(rectClient);

  _listBox.SetWindowPos(NULL, rectClient.left, rectClient.top, rectClient.Width(), rectClient.Height(), SWP_NOACTIVATE | SWP_NOZORDER);

 }

}

2. 在程序中添加悬浮窗口对象

上面一步只是给工程添加了一个悬浮窗口类, 但并没生成该类的实例. 这里创建该实例(在CMainFrame类中)

2.1 在主框架类声明中添加对象, 代码为:

protected:  

 CDock m_wndDock;

2.2 创建dockablePane的窗口, 在主框架的OnCreate()函数中

(注: 这里我建议在OnCreate函数中自动生成代码EnableAutoHidePanes(CBRS_ALIGN_ANY)的后面添加)

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

 ...

 EnableAutoHidePanes(CBRS_ALIGN_ANY);

 // 利用这里的CBRS_RIGHT来设置最初的窗口停靠的位置, 可以的取值是

 // CBRS_NOALIGN, CBRS_LEFT, CBRS_TOP, CBRS_RIGHT, CBRS_BOTTOM

 DWORD style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_RIGHT | CBRS_FLOAT_MULTI;

 if (!wndDock1.Create(

  // 该dock窗口的标题(如果可以有的话...)

  _T("Dock1"),

  // 该dock窗口的parent, 设置为this

  this,

  //  窗口的大小, 注意是"悬浮"的情况下的大小, 处于dock状态时大小与该值无关

  CRect(0, 0, 200, 200),

  // 该dock窗口是否有标题, 如果为FALSE, 则第一个字符串参数显示不出来

  TRUE,

  // 该dock窗口的ID值. 注意: 如果希望dock窗口的状态可以保存在注册表中(这样下次启动程序时仍保持该状态),  则该值必须的唯一的

  nID,

  // 

  style))

 {

  return FALSE;

 }

 ...



2.3去掉CDockablePane的Close按钮?

方法一:

在继承CDockablePane的类中重写CanBeClosed()方法: 

virtual BOOL CanBeClosed() const; ... BOOL COutputWnd::CanBeClosed() const { return FALSE;

}

方法二:


if (!m_wndView.Create(strFileView, this, CRect(0, 0, 250, 200), TRUE, ID_VIEW_VIEW,

  WS_CHILD | WS_VISIBLE | CBRS_LEFT | CBRS_HIDE_INPLACE | WS_CAPTION, AFX_CBRS_REGULAR_TABS, AFX_CBRS_RESIZE))在Create的时候 后面加上这样的参数设置AFX_CBRS_REGULAR_TABS, AFX_CBRS_RESIZE 就不会有那个关闭按钮了

2.4显示隐藏CDockablePane
m_wndFileView.ShowPane(TRUE,FALSE,TRUE);//显示

m_wndFileView.ShowPane(FALSE,FALSE,TRUE);//隐藏


2.5 给悬浮窗口添加icon, 暂时省略.

 

3. 设置窗口悬浮方式, 令窗口悬浮

3.1 设置窗口悬浮位置

这部分代码也应该在MainFrame类的OnCreate函数中, 而且紧跟创建悬浮窗口的后面.

设置悬浮位置只需要调用CDockablePane::EnableDocking即可

 m_wndDock.EnableDocking(CBRS_ALIGN_ANY);

其中, 参数可以是CBRS_ALIGN_TOP, CBRS_ALIGN_RIGHT, CBRS_ALIGN_BOTTOM, CBRS_ALIGN_ANY

3.2 令窗口悬浮

欲使一个CDockablePane对象悬浮, 只需要调用框架类的DockPane函数即可:

 DockPane(&m_wndDock);

但是若有另外一个悬浮窗口的对象需要和m_wndDock在一起显示, 构成一个组(就像VS的资源视力和类视图), 那么第二个悬浮窗口需要使用CDockablePane类的AttchToTabWnd函数, 代码如下:

 DockPane(&m_wndDock);

 CDockablePane *pTabbedBar = NULL;

 m_wndDock2.AttachToTabWnd(&m_wndDock, DM_SHOW, FALSE, &pTabbedBar);
最后我得到的效果图分割窗口加+悬浮窗口 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息