当前位置: 代码迷 >> 综合 >> 【MFC】CSplitterWnd 重载限定窗口调整范围
  详细解决方案

【MFC】CSplitterWnd 重载限定窗口调整范围

热度:9   发布时间:2023-10-19 11:47:25.0

 前言:

void CSplitterWnd::GetColumnInfo(int col, int& cxCur, int& cxMin) ;在使用拆分窗口时我的需要是想调整窗口大小在一定范围 不允许过小和隐藏,通过文档得知此代码设置窗口的当前宽度和最小宽度,但是在实际使用发现在调整窗口小于设定的cxMin时,竟然让窗口消失了,这完全与我的需求背道而驰,因此通过分析源码找到了 较为完美的解决方案,并记录笔记,欢迎朋友们交流互相学习。

 注:CSplitterWndEx是继承的CSplitterWnd 只是分割符更加好看了 没有其它拓展功能。

【MFC】CSplitterWnd 重载限定窗口调整范围

只能点击 【添加类(C)...】  手动继承CSplitterWndEx, 头文件如下设计 重载两个重要的 方法

#pragma once
#include "afxsplitterwndex.h"
class CUserSplitter :public CSplitterWndEx
{
public:CUserSplitter();virtual ~CUserSplitter();virtual void TrackRowSize(int y, int row);virtual void TrackColumnSize(int x, int col);DECLARE_MESSAGE_MAP()
};

其中TrackRowSize 是根据名称便知是调整行的尺寸的,源码中实现方法如下:

//路径 ..\atlmfc\src\mfc\winsplit.cpp  877行
void CSplitterWnd::TrackRowSize(int y, int row)
{ASSERT_VALID(this);ASSERT(m_nRows > 1);CPoint pt(0, y);ClientToScreen(&pt);GetPane(row, 0)->ScreenToClient(&pt);m_pRowInfo[row].nIdealSize = pt.y;      // new sizeif (pt.y < m_pRowInfo[row].nMinSize){//这里的判断是说如果当前行的新Size小于 设定的nMinSize 则移除这一行 // resized too smallm_pRowInfo[row].nIdealSize = 0; // make it go away    if (GetStyle() & SPLS_DYNAMIC_SPLIT)DeleteRow(row);}else if (m_pRowInfo[row].nCurSize + m_pRowInfo[row+1].nCurSize< pt.y + m_pRowInfo[row+1].nMinSize){//这个判断是说如果当前区域的下一行小于最小的nMinSize则移除下一行// not enough room for other paneif (GetStyle() & SPLS_DYNAMIC_SPLIT)DeleteRow(row + 1);}
}

根据它的判断方式我们便可以最小的改动去实现 限定窗口在一定范围内的缩放

首先重载如下

#include "UserSplitter.h"CUserSplitter::CUserSplitter()
{
}CUserSplitter::~CUserSplitter()
{
}
void CUserSplitter::TrackRowSize(int y, int row)
{ASSERT_VALID(this);ASSERT(m_nRows > 1);CPoint pt(0, y);ClientToScreen(&pt);GetPane(row, 0)->ScreenToClient(&pt);m_pRowInfo[row].nIdealSize = pt.y;      // new sizeif (pt.y < m_pRowInfo[row].nMinSize){// resized too smallm_pRowInfo[row].nIdealSize = m_pRowInfo[row].nMinSize; // 如果小于最小 则设为最小/*if (GetStyle() & SPLS_DYNAMIC_SPLIT)DeleteRow(row);*/}else if (m_pRowInfo[row].nCurSize + m_pRowInfo[row + 1].nCurSize< pt.y + m_pRowInfo[row + 1].nMinSize){//如果挤压旁边太小 则重新设定大小// not enough room for other pane/*if (GetStyle() & SPLS_DYNAMIC_SPLIT)DeleteRow(row + 1);*/m_pColInfo[row].nIdealSize = m_pColInfo[row].nCurSize + m_pColInfo[row + 1].nCurSize- m_pColInfo[row + 1].nMinSize;}
}
void CUserSplitter::TrackColumnSize(int x, int col)
{ASSERT_VALID(this);ASSERT(m_nCols > 1);CPoint pt(x, 0);ClientToScreen(&pt);GetPane(0, col)->ScreenToClient(&pt);m_pColInfo[col].nIdealSize = pt.x;      // new sizeif (pt.x < m_pColInfo[col].nMinSize){// resized too smallm_pColInfo[col].nIdealSize = m_pColInfo[col].nMinSize; // make it go away/*if (GetStyle() & SPLS_DYNAMIC_SPLIT)DeleteColumn(col);*/}else if (m_pColInfo[col].nCurSize + m_pColInfo[col + 1].nCurSize< pt.x + m_pColInfo[col + 1].nMinSize){// not enough room for other pane/*if (GetStyle() & SPLS_DYNAMIC_SPLIT)DeleteColumn(col + 1);*/m_pColInfo[col].nIdealSize = m_pColInfo[col].nCurSize + m_pColInfo[col + 1].nCurSize- m_pColInfo[col + 1].nMinSize;}
}

从上面代码可知,要限定大小则需要m_pColInfo 数组的数据

则使用时可以做如下设计

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{// TODO: 在此添加专用代码和/或调用基类int rec = m_SplitWnd.CreateStatic(this, 1, 2);m_SplitWnd.CreateView(0, 0, RUNTIME_CLASS(CUserTreeView), CSize(100, 100), pContext);m_SplitWnd.CreateView(0, 1, RUNTIME_CLASS(CUserTabView), CSize(100, 100), pContext);return  rec;//return CFrameWndEx::OnCreateClient(lpcs, pContext);
}
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{CFrameWndEx::OnSize(nType, cx, cy);// TODO: 在此处添加消息处理程序代码m_SplitWnd.SetColumnInfo(0, static_cast<int>(cx*0.2), static_cast<int>(cx*0.1));m_SplitWnd.SetColumnInfo(1, static_cast<int>(cx*0.8), static_cast<int>(cx*0.6));m_SplitWnd.RecalcLayout();
}