230 lines
5.3 KiB
C++
230 lines
5.3 KiB
C++
#include "stdafx.h"
|
|
#include "afxdialogex.h"
|
|
#include "CGridDialog.h"
|
|
#include "Resource.h"
|
|
|
|
BEGIN_MESSAGE_MAP(CGridDialog, CDialog)
|
|
ON_WM_SIZE()
|
|
ON_WM_LBUTTONDBLCLK()
|
|
ON_MESSAGE(WM_CHILD_CLOSED, &CGridDialog::OnChildClosed)
|
|
END_MESSAGE_MAP()
|
|
|
|
CGridDialog::CGridDialog() : CDialog()
|
|
{
|
|
}
|
|
|
|
BOOL CGridDialog::OnInitDialog()
|
|
{
|
|
m_hIcon = ::LoadIconA(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
|
|
SetIcon(m_hIcon, FALSE);
|
|
|
|
CDialog::OnInitDialog();
|
|
return TRUE;
|
|
}
|
|
|
|
void CGridDialog::SetGrid(int rows, int cols)
|
|
{
|
|
m_rows = rows;
|
|
m_cols = cols;
|
|
m_max = rows * cols;
|
|
LayoutChildren();
|
|
}
|
|
|
|
BOOL CGridDialog::AddChild(CDialog* pDlg)
|
|
{
|
|
if (!pDlg || !::IsWindow(pDlg->GetSafeHwnd()) || m_children.size() >= m_max)
|
|
return FALSE;
|
|
|
|
pDlg->SetParent(this);
|
|
pDlg->ShowWindow(SW_SHOW);
|
|
|
|
// 去掉标题栏和调整大小
|
|
LONG style = ::GetWindowLong(pDlg->GetSafeHwnd(), GWL_STYLE);
|
|
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_SIZEBOX | WS_BORDER);
|
|
::SetWindowLong(pDlg->GetSafeHwnd(), GWL_STYLE, style);
|
|
::SetWindowPos(pDlg->GetSafeHwnd(), nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
|
|
m_children.push_back(pDlg);
|
|
LayoutChildren();
|
|
return TRUE;
|
|
}
|
|
|
|
void CGridDialog::RemoveChild(CDialog* pDlg)
|
|
{
|
|
auto it = std::find(m_children.begin(), m_children.end(), pDlg);
|
|
if (it != m_children.end())
|
|
{
|
|
(*it)->ShowWindow(SW_HIDE);
|
|
(*it)->SetParent(nullptr);
|
|
m_children.erase(it);
|
|
|
|
// 删除 m_origState 中对应条目
|
|
auto itState = m_origState.find(pDlg);
|
|
if (itState != m_origState.end())
|
|
m_origState.erase(itState);
|
|
|
|
// 如果关闭的子窗口是当前最大化窗口,重置 m_pMaxChild
|
|
if (m_pMaxChild == pDlg)
|
|
m_pMaxChild = nullptr;
|
|
|
|
LayoutChildren();
|
|
}
|
|
}
|
|
|
|
LRESULT CGridDialog::OnChildClosed(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CDialog* pDlg = (CDialog*)wParam;
|
|
RemoveChild(pDlg);
|
|
return 0;
|
|
}
|
|
|
|
void CGridDialog::LayoutChildren()
|
|
{
|
|
if (m_children.size() == 0) {
|
|
// 恢复父窗口标题栏
|
|
if (m_parentStyle != 0)
|
|
{
|
|
::SetWindowLong(m_hWnd, GWL_STYLE, m_parentStyle);
|
|
::SetWindowPos(m_hWnd, nullptr, 0, 0, 0, 0,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
m_parentStyle = 0;
|
|
}
|
|
ShowWindow(SW_HIDE);
|
|
return;
|
|
}
|
|
|
|
if (m_rows <= 0 || m_cols <= 0 || m_children.empty() || m_pMaxChild != nullptr)
|
|
return;
|
|
|
|
CRect rcClient;
|
|
GetClientRect(&rcClient);
|
|
|
|
int w = rcClient.Width() / m_cols;
|
|
int h = rcClient.Height() / m_rows;
|
|
|
|
for (size_t i = 0; i < m_children.size(); ++i)
|
|
{
|
|
int r = (int)i / m_cols;
|
|
int c = (int)i % m_cols;
|
|
|
|
if (r >= m_rows)
|
|
break; // 超过网格范围
|
|
|
|
int x = c * w;
|
|
int y = r * h;
|
|
|
|
m_children[i]->MoveWindow(x, y, w, h, TRUE);
|
|
m_children[i]->ShowWindow(SW_SHOW);
|
|
}
|
|
}
|
|
|
|
void CGridDialog::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CDialog::OnSize(nType, cx, cy);
|
|
|
|
if (m_pMaxChild == nullptr) {
|
|
LayoutChildren();
|
|
}
|
|
else {
|
|
// 最大化状态下,保持铺满父对话框
|
|
CRect rcClient;
|
|
GetClientRect(&rcClient);
|
|
m_pMaxChild->MoveWindow(rcClient, TRUE);
|
|
}
|
|
}
|
|
|
|
void CGridDialog::OnLButtonDblClk(UINT nFlags, CPoint point)
|
|
{
|
|
// 如果当前有最大化的子窗口,双击任何地方都恢复
|
|
if (m_pMaxChild != nullptr)
|
|
{
|
|
// 恢复子窗口样式和位置
|
|
for (auto& kv : m_origState)
|
|
{
|
|
CDialog* dlg = kv.first;
|
|
const ChildState& state = kv.second;
|
|
|
|
::SetWindowLong(dlg->GetSafeHwnd(), GWL_STYLE, state.style);
|
|
::SetWindowPos(dlg->GetSafeHwnd(), nullptr, 0, 0, 0, 0,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
|
|
dlg->MoveWindow(state.rect, TRUE);
|
|
dlg->ShowWindow(SW_SHOW);
|
|
}
|
|
|
|
// 恢复父窗口标题栏
|
|
if (m_parentStyle != 0)
|
|
{
|
|
::SetWindowLong(m_hWnd, GWL_STYLE, m_parentStyle);
|
|
::SetWindowPos(m_hWnd, nullptr, 0, 0, 0, 0,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
m_parentStyle = 0;
|
|
}
|
|
|
|
// 刷新父窗口
|
|
m_pMaxChild = nullptr;
|
|
m_origState.clear();
|
|
LayoutChildren();
|
|
return; // 已处理,返回
|
|
}
|
|
|
|
// 没有最大化子窗口,则按原逻辑找到点击的子窗口进行最大化
|
|
for (auto dlg : m_children)
|
|
{
|
|
CRect rc;
|
|
dlg->GetWindowRect(&rc);
|
|
ScreenToClient(&rc);
|
|
|
|
if (rc.PtInRect(point))
|
|
{
|
|
// 保存所有子窗口原始状态
|
|
m_origState.clear();
|
|
for (auto d : m_children)
|
|
{
|
|
ChildState state;
|
|
d->GetWindowRect(&state.rect);
|
|
ScreenToClient(&state.rect);
|
|
state.style = ::GetWindowLong(d->GetSafeHwnd(), GWL_STYLE);
|
|
m_origState[d] = state;
|
|
}
|
|
|
|
// 最大化点击的子窗口
|
|
LONG style = m_origState[dlg].style;
|
|
style |= (WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
|
|
::SetWindowLong(dlg->GetSafeHwnd(), GWL_STYLE, style);
|
|
::SetWindowPos(dlg->GetSafeHwnd(), nullptr, 0, 0, 0, 0,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
|
|
// 隐藏父窗口标题栏
|
|
if (m_parentStyle == 0)
|
|
m_parentStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
|
|
LONG parentStyle = m_parentStyle & ~(WS_CAPTION | WS_THICKFRAME);
|
|
::SetWindowLong(m_hWnd, GWL_STYLE, parentStyle);
|
|
::SetWindowPos(m_hWnd, nullptr, 0, 0, 0, 0,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
|
|
// 全屏显示子窗口
|
|
CRect rcClient;
|
|
GetClientRect(&rcClient);
|
|
dlg->MoveWindow(rcClient, TRUE);
|
|
m_pMaxChild = dlg;
|
|
|
|
// 隐藏其他子窗口
|
|
for (auto d : m_children)
|
|
if (d != dlg) d->ShowWindow(SW_HIDE);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
CDialog::OnLButtonDblClk(nFlags, point);
|
|
}
|
|
|
|
BOOL CGridDialog::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) {
|
|
return TRUE;// 屏蔽Enter和ESC关闭对话
|
|
}
|
|
return CDialog::PreTranslateMessage(pMsg);
|
|
}
|