📄 dlgsplitter.cpp
字号:
// create the scroll bar when necessary
if (!CreateScrollBarCtrl(SBS_VERT, AFX_IDW_VSCROLL_FIRST + row))
AfxThrowResourceException();
pScrollBar = GetDlgItem(AFX_IDW_VSCROLL_FIRST + row);
}
pScrollBar->ShowWindow(m_bHasVScroll ? SW_SHOW : SW_HIDE);
}
// show/destroy size box if necessary
if (m_bHasVScroll && m_bHasHScroll)
{
pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
if (pScrollBar == NULL)
{
// create size box when necessary
if (!CreateScrollBarCtrl(SBS_SIZEBOX|WS_DISABLED, AFX_IDW_SIZE_BOX))
AfxThrowResourceException();
pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
}
pScrollBar->ShowWindow(SW_SHOW);
}
else
{
// the size box can be destroyed instead of hidden
pScrollBar = GetDlgItem(AFX_IDW_SIZE_BOX);
if (pScrollBar != NULL)
pScrollBar->DestroyWindow();
}
// Note: call RecalcLayout for the new layout to take effect
}
/////////////////////////////////////////////////////////////////////////////
// CDlgSplitterWnd client operations/overridables
void CDlgSplitterWnd::DeleteView(int row, int col)
{
ASSERT_VALID(this);
// if active child is being deleted - activate next
CWnd* pPane = GetPane(row, col);
ASSERT_KINDOF(CView, pPane);
if (GetActivePane() == pPane)
ActivateNext(FALSE);
// default implementation assumes view will auto delete in PostNcDestroy
pPane->DestroyWindow();
}
void CDlgSplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType,
const CRect& rectArg)
{
// if pDC == NULL, then just invalidate
if (pDC == NULL)
{
RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
return;
}
ASSERT_VALID(pDC);
// otherwise, actually draw
CRect rect = rectArg;
switch (nType)
{
case splitBorder:
ASSERT(afxData.bWin4);
pDC->Draw3dRect(rect, afxData.clrBtnShadow, afxData.clrBtnHilite);
rect.InflateRect(-CX_BORDER, -CY_BORDER);
pDC->Draw3dRect(rect, afxData.clrWindowFrame, afxData.clrBtnFace);
return;
case splitIntersection:
ASSERT(!afxData.bWin4);
break;
case splitBox:
if (afxData.bWin4)
{
pDC->Draw3dRect(rect, afxData.clrBtnFace, afxData.clrWindowFrame);
rect.InflateRect(-CX_BORDER, -CY_BORDER);
pDC->Draw3dRect(rect, afxData.clrBtnHilite, afxData.clrBtnShadow);
rect.InflateRect(-CX_BORDER, -CY_BORDER);
break;
}
// fall through...
case splitBar:
if (!afxData.bWin4)
{
pDC->Draw3dRect(rect, afxData.clrBtnHilite, afxData.clrBtnShadow);
rect.InflateRect(-CX_BORDER, -CY_BORDER);
}
break;
default:
ASSERT(FALSE); // unknown splitter type
}
// fill the middle
COLORREF clr = afxData.clrBtnFace;
pDC->FillSolidRect(rect, clr);
}
/////////////////////////////////////////////////////////////////////////////
// Dynamic row/col split etc
AFX_STATIC int AFXAPI _AfxCanSplitRowCol(CDlgSplitterWnd::CRowColInfo* pInfoBefore,
int nBeforeSize, int nSizeSplitter)
// request to split Before row at point nBeforeSize
// returns size of new pane (nBeforeSize will be new size of Before pane)
// return -1 if not big enough
{
ASSERT(pInfoBefore->nCurSize > 0);
ASSERT(pInfoBefore->nMinSize > 0);
ASSERT(nBeforeSize <= pInfoBefore->nCurSize);
// space gets take from before pane (weird UI for > 2 splits)
if (nBeforeSize < pInfoBefore->nMinSize)
{
TRACE0("Warning: split too small to fit in a new pane.\n");
return -1;
}
int nNewSize = pInfoBefore->nCurSize - nBeforeSize - nSizeSplitter;
if (nBeforeSize < pInfoBefore->nMinSize)
{
TRACE0("Warning: split too small to shrink old pane.\n");
return -1;
}
if (nNewSize < (pInfoBefore+1)->nMinSize)
{
TRACE0("Warning: split too small to create new pane.\n");
return -1;
}
return nNewSize;
}
BOOL CDlgSplitterWnd::SplitRow(int cyBefore)
{
ASSERT_VALID(this);
ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
ASSERT(m_pDynamicViewClass != NULL);
ASSERT(m_nRows < m_nMaxRows);
cyBefore -= m_cyBorder;
int rowNew = m_nRows;
int cyNew = _AfxCanSplitRowCol(&m_pRowInfo[rowNew-1], cyBefore, m_cySplitter);
if (cyNew == -1)
return FALSE; // too small to split
// create the scroll bar first (so new views can see that it is there)
if (m_bHasVScroll &&
!CreateScrollBarCtrl(SBS_VERT, AFX_IDW_VSCROLL_FIRST + rowNew))
{
TRACE0("Warning: SplitRow failed to create scroll bar.\n");
return FALSE;
}
m_nRows++; // bump count during view creation
// create new views to fill the new row (RecalcLayout will position)
for (int col = 0; col < m_nCols; col++)
{
CSize size(m_pColInfo[col].nCurSize, cyNew);
if (!CreateView(rowNew, col, m_pDynamicViewClass, size, NULL))
{
TRACE0("Warning: SplitRow failed to create new row.\n");
// delete anything we partially created 'col' = # columns created
while (col > 0)
DeleteView(rowNew, --col);
if (m_bHasVScroll)
GetDlgItem(AFX_IDW_VSCROLL_FIRST + rowNew)->DestroyWindow();
m_nRows--; // it didn't work out
return FALSE;
}
}
// new parts created - resize and re-layout
m_pRowInfo[rowNew-1].nIdealSize = cyBefore;
m_pRowInfo[rowNew].nIdealSize = cyNew;
ASSERT(m_nRows == rowNew+1);
RecalcLayout();
return TRUE;
}
BOOL CDlgSplitterWnd::SplitColumn(int cxBefore)
{
ASSERT_VALID(this);
ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
ASSERT(m_pDynamicViewClass != NULL);
ASSERT(m_nCols < m_nMaxCols);
cxBefore -= m_cxBorder;
int colNew = m_nCols;
int cxNew = _AfxCanSplitRowCol(&m_pColInfo[colNew-1], cxBefore, m_cxSplitter);
if (cxNew == -1)
return FALSE; // too small to split
// create the scroll bar first (so new views can see that it is there)
if (m_bHasHScroll &&
!CreateScrollBarCtrl(SBS_HORZ, AFX_IDW_HSCROLL_FIRST + colNew))
{
TRACE0("Warning: SplitRow failed to create scroll bar.\n");
return FALSE;
}
m_nCols++; // bump count during view creation
// create new views to fill the new column (RecalcLayout will position)
for (int row = 0; row < m_nRows; row++)
{
CSize size(cxNew, m_pRowInfo[row].nCurSize);
if (!CreateView(row, colNew, m_pDynamicViewClass, size, NULL))
{
TRACE0("Warning: SplitColumn failed to create new column.\n");
// delete anything we partially created 'col' = # columns created
while (row > 0)
DeleteView(--row, colNew);
if (m_bHasHScroll)
GetDlgItem(AFX_IDW_HSCROLL_FIRST + colNew)->DestroyWindow();
m_nCols--; // it didn't work out
return FALSE;
}
}
// new parts created - resize and re-layout
m_pColInfo[colNew-1].nIdealSize = cxBefore;
m_pColInfo[colNew].nIdealSize = cxNew;
ASSERT(m_nCols == colNew+1);
RecalcLayout();
return TRUE;
}
void CDlgSplitterWnd::DeleteRow(int rowDelete)
{
ASSERT_VALID(this);
ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
ASSERT(m_nRows > 1);
ASSERT(rowDelete < m_nRows);
int rowActive, colActive;
if (GetActivePane(&rowActive, &colActive) != NULL && rowActive == rowDelete)
{
if (++rowActive >= m_nRows)
rowActive = 0;
SetActivePane(rowActive, colActive);
}
CWnd* pScrollDel = m_bHasVScroll ?
GetDlgItem(AFX_IDW_VSCROLL_FIRST+rowDelete) : NULL;
for (int col = 0; col < m_nCols; col++)
{
DeleteView(rowDelete, col);
for (int row = rowDelete+1; row < m_nRows; row++)
{
CWnd* pPane = GetPane(row, col);
ASSERT(pPane != NULL);
pPane->SetDlgCtrlID(IdFromRowCol(row-1, col));
if (m_bHasVScroll && col == m_nCols-1)
{
CWnd* pScroll = GetDlgItem(AFX_IDW_VSCROLL_FIRST+row);
if (pScroll != NULL)
pScroll->SetDlgCtrlID(AFX_IDW_VSCROLL_FIRST+row-1);
}
}
}
m_nRows--;
if (pScrollDel != NULL)
pScrollDel->DestroyWindow();
RecalcLayout(); // re-assign the space
}
void CDlgSplitterWnd::DeleteColumn(int colDelete)
{
ASSERT_VALID(this);
ASSERT(GetStyle() & SPLS_DYNAMIC_SPLIT);
ASSERT(m_nCols > 1);
ASSERT(colDelete < m_nCols);
int rowActive, colActive;
if (GetActivePane(&rowActive, &colActive) != NULL && colActive == colDelete)
{
if (++colActive >= m_nCols)
colActive = 0;
SetActivePane(rowActive, colActive);
}
CWnd* pScrollDel = m_bHasHScroll ?
GetDlgItem(AFX_IDW_HSCROLL_FIRST+colDelete) : NULL;
for (int row = 0; row < m_nRows; row++)
{
DeleteView(row, colDelete);
for (int col = colDelete+1; col < m_nCols; col++)
{
CWnd* pPane = GetPane(row, col);
ASSERT(pPane != NULL);
pPane->SetDlgCtrlID(IdFromRowCol(row, col-1));
if (m_bHasHScroll && row == m_nRows-1)
{
CWnd* pScroll = GetDlgItem(AFX_IDW_HSCROLL_FIRST+col);
if (pScroll != NULL)
pScroll->SetDlgCtrlID(AFX_IDW_HSCROLL_FIRST+col-1);
}
}
}
m_nCols--;
if (pScrollDel != NULL)
pScrollDel->DestroyWindow();
RecalcLayout(); // re-assign the space
}
/////////////////////////////////////////////////////////////////////////////
// CDlgSplitterWnd tracking support
// like GetClientRect but inset by shared scrollbars
void CDlgSplitterWnd::GetInsideRect(CRect& rect) const
{
ASSERT_VALID(this);
GetClientRect(rect);
ASSERT(rect.left == 0 && rect.top == 0);
// subtract space for 3d borders
rect.InflateRect(-m_cxBorder, -m_cyBorder);
// subtract scrollbar clearance
if (m_bHasVScroll)
rect.right -= afxData.cxVScroll - CX_BORDER;
if (m_bHasHScroll)
rect.bottom -= afxData.cyHScroll - CY_BORDER;
}
void CDlgSplitterWnd::StartTracking(int ht)
{
ASSERT_VALID(this);
if (ht == noHit)
return;
// GetHitRect will restrict 'm_rectLimit' as appropriate
GetInsideRect(m_rectLimit);
if (ht >= splitterIntersection1 && ht <= splitterIntersection225)
{
// split two directions (two tracking rectangles)
int row = (ht - splitterIntersection1) / 15;
int col = (ht - splitterIntersection1) % 15;
GetHitRect(row + vSplitterBar1, m_rectTracker);
int yTrackOffset = m_ptTrackOffset.y;
m_bTracking2 = TRUE;
GetHitRect(col + hSplitterBar1, m_rectTracker2);
m_ptTrackOffset.y = yTrackOffset;
}
else if (ht == bothSplitterBox)
{
// hit on splitter boxes (for keyboard)
GetHitRect(vSplitterBox, m_rectTracker);
int yTrackOffset = m_ptTrackOffset.y;
m_bTracking2 = TRUE;
GetHitRect(hSplitterBox, m_rectTracker2);
m_ptTrackOffset.y = yTrackOffset;
// center it
m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2);
m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0);
}
else
{
// only hit one bar
GetHitRect(ht, m_rectTracker);
}
//下面加注释的将从程序中删去。
// allow active view to preserve focus before taking it away
//CView* pView = (CView*)GetActivePane();
//if (pView != NULL && pView->IsKindOf(RUNTIME_CLASS(CView)))
//{
//ASSERT_VALID(pView);
//CFrameWnd* pFrameWnd = GetParentFrame();
//ASSERT_VALID(pFrameWnd);
//pView->OnActivateFrame(WA_INACTIVE, pFrameWnd);
//}
// steal focus and capture
SetCapture();
SetFocus();
// make sure no updates are pending
RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
// set tracking state and appropriate cursor
m_bTracking = TRUE;
OnInvertTracker(m_rectTracker);
if (m_bTracking2)
OnInvertTracker(m_rectTracker2);
m_htTrack = ht;
SetSplitCursor(ht);
}
void CDlgSplitterWnd::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 size
if (pt.y < m_pRowInfo[row].nMinSize)
{
// resized too small
m_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)
{
// not enough room for other pane
if (GetStyle() & SPLS_DYNAMIC_SPLIT)
DeleteRow(row + 1);
}
}
void CDlgSplitterWnd::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 size
if (pt.x < m_pColInfo[col].nMinSize)
{
// resized too small
m_pColInfo[col].nIdealSize = 0; // 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);
}
}
void CDlgSplitterWnd::StopTracking(BOOL bAccept)
{
ASSERT_VALID(this);
if (!m_bTracking)
return;
ReleaseCapture();
// erase tracker rectangle
OnInvertTracker(m_rectTracker);
if (m_bTracking2)
OnInvertTracker(m_rectTracker2);
m_bTracking = m_bTracking2 = FALSE;
// save old active view
CWnd* pOldActiveView = GetActivePane();
// m_rectTracker is set to the new splitter position (without border)
// (so, adjust relative to where the border will be)
m_rectTracker.OffsetRect(-CX_BORDER , -CY_BORDER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -