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);
	}
}
相关推荐
zhouwy11321 小时前
Linux文件系统与IO编程
linux·c++
王老师青少年编程1 天前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮1 天前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
样例过了就是过了1 天前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
谭欣辰1 天前
C++ 排列组合完整指南
开发语言·c++·算法
橙子也要努力变强1 天前
信号捕捉底层机制-机理篇2
linux·服务器·c++
盐焗鹌鹑蛋1 天前
【C++】stack和queue类
c++
郝学胜-神的一滴1 天前
罗德里格斯旋转公式(Rodrigues‘ Rotation Formula)完整推导
c++·unity·godot·图形渲染·three.js·unreal
lzh200409191 天前
深入理解进程:从PCB内核结构到写时拷贝的底层实战
linux·c++
aseity1 天前
跨平台项目中QString 与 非Qt 跨平台动态库在字符集上的一个实用的互操作约定.
c++·经验分享