MFC实现堆栈窗口:多个子界面可任意切换

1、效果

  在Qt中可使用QStackedWidget控件直接拖动布置即可实现,但在MFC中并未提供类似的控件,因此需要自己简单实现。

2、实现原理

  实现原理比较简单,父级对话框在显示的区域部分,通过切换子对话框即可实现。子对话框去掉边框后移动到父级对话框的显示区域即可。需要注意的是子对话框需要用非模态方式创建,同时记得在父级对话框销毁指针。

3、源码

cpp 复制代码
// SwitchChildrenDlgDlg.h: 头文件

#pragma once

#include "CChild1Dlg.h"
#include "CChild2Dlg.h"

// CSwitchChildrenDlgDlg 对话框
class CSwitchChildrenDlg : public CDialogEx
{
// 构造
public:
	CSwitchChildrenDlg(CWnd* pParent = nullptr);	// 标准构造函数
	virtual ~CSwitchChildrenDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_SWITCHCHILDRENDLG_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	//afx_msg void OnSize(UINT nType, int cx, int cy);
	afx_msg void OnBnClickedOk();
	afx_msg void OnBnClickedCancel();
	afx_msg void OnCbnSelchangeComboType();
private:
	CChild1Dlg* m_Child1Dlg;
	CChild2Dlg* m_Child2Dlg;
	CComboBox m_cmbType;
};
cpp 复制代码
CSwitchChildrenDlg::CSwitchChildrenDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_SWITCHCHILDRENDLG_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

CSwitchChildrenDlg::~CSwitchChildrenDlg()
{
	if (m_Child1Dlg)
	{
		delete m_Child1Dlg;
		m_Child1Dlg = nullptr;
	}

	if (m_Child2Dlg)
	{
		delete m_Child2Dlg;
		m_Child2Dlg = nullptr;
	}
}

BOOL CSwitchChildrenDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将"关于..."菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	if (!m_Child1Dlg)
	{
		m_Child1Dlg = new CChild1Dlg(this);
		m_Child1Dlg->Create(IDD_CHILD1_DLG, this);
	}

	if (!m_Child2Dlg)
	{
		m_Child2Dlg = new CChild2Dlg(this);
		m_Child2Dlg->Create(IDD_CHILD2_DLG, this);
	}

	m_cmbType.AddString(_T("地域"));
	m_cmbType.AddString(_T("范围"));
	m_cmbType.SetCurSel(0);
	OnCbnSelchangeComboType();

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CSwitchChildrenDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	if (m_cmbType.GetCurSel() == 0)
	{
		m_Child1Dlg->OnBnClickedOk();
	}
	else if (m_cmbType.GetCurSel() == 1)
	{
		m_Child2Dlg->OnBnClickedOk();
	}

	CDialogEx::OnOK();
}

void CSwitchChildrenDlg::OnCbnSelchangeComboType()
{
	// TODO: 在此添加控件通知处理程序代码
	CRect cltrect;
	GetClientRect(cltrect);//获取当前主对话框的坐标

	if (m_cmbType.GetCurSel() == 0)
	{
		m_Child1Dlg->ShowWindow(SW_SHOW);
		m_Child2Dlg->ShowWindow(SW_HIDE);
		//设置动态对话框的位置
		m_Child1Dlg->SetWindowPos(&wndTop, cltrect.left + 10, cltrect.top + 30, cltrect.Width(), cltrect.Height() - 100, SWP_NOACTIVATE);
	}
	else if (m_cmbType.GetCurSel() == 1)
	{
		if (!m_Child2Dlg)
		{
			m_Child2Dlg = new CChild2Dlg(this);
			m_Child2Dlg->Create(IDD_CHILD2_DLG, this);
		}
		m_Child2Dlg->ShowWindow(SW_SHOW);
		m_Child1Dlg->ShowWindow(SW_HIDE);
		//设置动态对话框的位置
		m_Child2Dlg->SetWindowPos(&wndTop, cltrect.left + 10, cltrect.top + 30, cltrect.Width(), cltrect.Height() - 100, SWP_NOACTIVATE);
	}
}
相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK2 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
卷无止境2 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境2 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴3 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
卷无止境5 天前
C++ 的Eigen 库全解析
c++
卷无止境5 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端
郝学胜_神的一滴5 天前
CMake 27:缓存变量的特性、语法、类型与实操全解
c++·cmake
博客18007 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴7 天前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake