devstudio_like_controlbar.shtml
来自「mfc资源大全包含MFC编程各个方面的源码」· SHTML 代码 · 共 489 行 · 第 1/2 页
SHTML
489 行
}
}
</tt></PRE></FONT>
Then override your OnPaint() function to call RecalcLayout() before it does its painting:
<FONT COLOR="#990000"><TT><PRE>
void CGripDialogBar::OnPaint()
{
// Notice here we break the do not call
// the base class OnPaint Rule. This is
// because we do not set up our own DC
// here so calling the base is OK and also
// required, otherwise we need to redo
// what the base already does for us
RecalcLayout();
CDialogBar::OnPaint();
}
</tt></PRE></FONT>
We have now fixed the floating caption bug, but we have now introduced a new bug. We have lost double
click support. Look at how the drag frame is now drawn and I think you will see why:
<p><img src="devstudio_like_controlbar3.gif"></p>
By default, the drag frame is drawn around the dock control window in its entirety. Because our control
is offset inside the docking frame, the docking frame actually changes position the first time we
click the mouse button. Since the window has moved, the second click gets sent to our control window
and not the floating frame. To remedy this, we will need to write a new class which overrides the
docking functionality of our window.
(Just a forewarning: We are about to delve into <afxpriv.h>. Although this is not a crime, the
reader should be aware that this class may or may NOT work with future MFC versions.) The docking
support for MFC windows has its own class, CDockExtent. One single call to StartDrag(), or
ToggleDocking(), starts the docking process. Fortunately, these functions are virtual meaning we can
override the current behavior to provide our own. Our new class CExDockExtent will override
StartDrag() and also provide its own overridable, AdjustWindowForFloat() which will make this class
very generic and apply to many if not all possibilities. The default will be designed to work with our
CGripDialogBar:
<FONT COLOR="#990000"><TT><PRE>
class CExDockContext : public CDockContext
{
public:
CExDockContext(CControlBar* pBar);
virtual ~CExDockContext();
// Drag Operations
virtual void StartDrag(CPoint pt);
protected:
virtual void AdjustWindowForFloat(CRect& rect);
};
</tt></PRE></FONT>
We will now override the start drag function. Most of it will be exactly the same as the base class.
I will put in comments where we call our AdjustWindowForFloat(). It needs to be called a total of
three times.
<FONT COLOR="#990000"><TT><PRE>
void CExDockContext::StartDrag(CPoint pt)
{
ASSERT_VALID(m_pBar);
m_bDragging = TRUE;
InitLoop();
if (m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC)
{
// get true bar size (including borders)
CRect rect;
m_pBar->GetWindowRect(rect);
// This is our added funtionality
// This overridable allows you
// to adjust the window rect so that
// you can hide controls like a caption
// bar from view
//NewCode--> AdjustWindowForFloat(rect);
m_ptLast = pt;
CSize sizeHorz = m_pBar->CalcDynamicLayout(0,
LM_HORZ | LM_HORZDOCK);
CSize sizeVert = m_pBar->CalcDynamicLayout(0,
LM_VERTDOCK);
CSize sizeFloat = m_pBar->CalcDynamicLayout(0,
LM_HORZ | LM_MRUWIDTH);
m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz);
m_rectDragVert = CRect(rect.TopLeft(), sizeVert);
// calculate frame dragging rectangle
m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat);
m_rectFrameDragVert = CRect(rect.TopLeft(), sizeFloat);
#ifdef _MAC
CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz,
WS_THICKFRAME | WS_CAPTION, WS_EX_FORCESIZEBOX);
CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert,
WS_THICKFRAME | WS_CAPTION, WS_EX_FORCESIZEBOX);
#else
CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
#endif
m_rectFrameDragHorz.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
m_rectFrameDragVert.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
}
else if (m_pBar->m_dwStyle & CBRS_SIZE_FIXED)
{
// get true bar size (including borders)
CRect rect;
m_pBar->GetWindowRect(rect);
// This is our added funtionality
// This overridable allows you
// to adjust the window rect so that
// you can hide controls like a caption
// bar from view
//NewCode--> AdjustWindowForFloat(rect);
m_ptLast = pt;
CSize sizeHorz = m_pBar->CalcDynamicLayout(-1,
LM_HORZ | LM_HORZDOCK);
CSize sizeVert = m_pBar->CalcDynamicLayout(-1, LM_VERTDOCK);
// calculate frame dragging rectangle
m_rectFrameDragHorz = m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz);
m_rectFrameDragVert = m_rectDragVert = CRect(rect.TopLeft(), sizeVert);
CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
m_rectFrameDragHorz.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
m_rectFrameDragVert.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
}
else
{
// get true bar size (including borders)
CRect rect;
m_pBar->GetWindowRect(rect);
// This is our added funtionality
// This overridable allows you
// to adjust the window rect so that
// you can hide controls like a caption
// bar from view
//NewCode--> AdjustWindowForFloat(rect);
m_ptLast = pt;
BOOL bHorz = HORZF(m_dwStyle);
DWORD dwMode = !bHorz ? (LM_HORZ |
LM_HORZDOCK):LM_VERTDOCK;
CSize size = m_pBar->CalcDynamicLayout(-1, dwMode);
// calculate inverted dragging rect
if (bHorz)
{
m_rectDragHorz = rect;
m_rectDragVert = CRect(CPoint(pt.x - rect.Height()/2, rect.top), size);
}
else // vertical orientation
{
m_rectDragVert = rect;
m_rectDragHorz = CRect(CPoint(rect.left, pt.y - rect.Width()/2), size);
}
// calculate frame dragging rectangle
m_rectFrameDragHorz = m_rectDragHorz;
m_rectFrameDragVert = m_rectDragVert;
CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
m_rectFrameDragHorz.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
m_rectFrameDragVert.InflateRect(-afxData.cxBorder2, -afxData.cyBorder2);
}
// adjust rectangles so that point is inside
AdjustRectangle(m_rectDragHorz, pt);
AdjustRectangle(m_rectDragVert, pt);
AdjustRectangle(m_rectFrameDragHorz, pt);
AdjustRectangle(m_rectFrameDragVert, pt);
// initialize tracking state and enter tracking loop
m_dwOverDockStyle = CanDock();
Move(pt); // call it here to handle special keys
Track();
}
</tt></PRE></FONT>
With that complete we simply call our new AdjustWindowForFloat() to make any modifications to the
rectangle before the drag frame is drawn. Remember, that we moved our control up to hide the caption
bar so we would not see it. So in our AdjustWindowForFloat() we will undo the coordinate move and
pass the unmodified coordinates:
<FONT COLOR="#990000"><TT><PRE>
void CExDockContext::AdjustWindowForFloat(CRect& rect)
{
// Overridable to adjust floating frame
// size for added controls you don not
// want to see in the floating state
// Default behavior is to move window
// up enough to hide the caption bar
if(m_pBar->IsFloating())
rect.top += (GetSystemMetrics(SM_CYCAPTION)
+ GetSystemMetrics(SM_CYFRAME));
}
</tt></PRE></FONT>
There is one last step. We now need to tell our CGripDialogBar to use our overridden docking support
rather than the default. This is relatively easy to do. . The m_pDockContext object is a pointer
which is setup in the call to EnableDocking(). If a pointer already exists the framework uses that
one. This means the in our OnInitDialogBar(), which gets called before EnableDocking() in OnCreate(),
we can allocate the m_pDockContext and the framework now uses our overridden docking support.
The completed OnInitDialogBar(). The new InInitDialogBar() function now looks like this:
<FONT COLOR="#990000"><TT><PRE>
BOOL CGripDialogBar::OnInitDialogBar()
{
// Add our caption
ModifyStyle(0, WS_CAPTION);
// Setup up the overidded context for Docking
// We will use this context to provide our own
// docking functionality.
// By doing this ourselves now instead of during
// Enable docking we are able to replace the
// original member variable with our new class
// since all our changes occur in virtual
// functions.
if (m_pDockContext == NULL)
m_pDockContext = new CExDockContext(this);
ASSERT(m_pDockContext);
// Call Base Class
CInitDialogBar::OnInitDialogBar();
return TRUE;
}
</tt></PRE></FONT>
The m_pDockContext object is deleted by the base class destructor you do NOT have to delete it yourself.
That pretty much covers it. You should now have a control based on a CDialogBar that has a gripper
caption at the top like DevStudios. There is still some missing functionality like the close button.
If you are interested in a more complete version, including close button support, flicker free drawing,
and other enhancements, along with a sample of its use stop by http://avenger.mri.psu.edu/ntpage.html.
Look under the column to the right under 揝tupid MFC Tricks
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?