devstudio_like_controlbar.shtml
来自「mfc资源大全包含MFC编程各个方面的源码」· SHTML 代码 · 共 489 行 · 第 1/2 页
SHTML
489 行
<HTML>
<!-- Header information-->
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Author" CONTENT="Nikolay Sokratov">
<TITLE>Section - Title</TITLE>
</HEAD>
<!-- Set background properties -->
<body background="../fancyhome/back.gif" bgcolor="#FFFFFF" link="#B50029" vlink="#8E2323" alink="#FF0000">
<!-- A word from our sponsors... -->
<table WIDTH="100%">
<tr WIDTH="100%"><td align=center><!--#exec cgi="/cgi/ads.cgi"--><td></tr>
</table>
<!-- Article Title -->
<CENTER><H3><FONT COLOR="#AOAO99">
A DevStudio like CControlBar
</FONT></H3></CENTER>
<CENTER><H3><HR></H3></CENTER>
<!-- Author and contact details -->
This article was contributed by <A HREF="mailto:acp107@psu.edu">Alger Pike</A>.
<!-- Sample image and source code/demo project -->
<!-- The article... -->
<p>There has been much talk of late of making dockable views that have the features of the DevStudio
workspace. Most of the code that I have seen to date revolves around turning a view into a docking
window. They also don't mention how to put a grip bar at the top of these windows. There are many
types of controls, inclding the docking views, that would benefit from this treatment, and in particular
a CDialogControl. In many respects, we are already almost there; a CDialogBar already supports docking
by default. All we need to do, is include support for the caption with the dock grippers and close
button. This as it turns out is easier said than done. However, it is possible and when we are done
we will have a CGripDialogBar that looks like this:
<p><img src="devstudio_like_controlbar1.gif"></p>
Why is a caption at the top of a CDialogBar a good thing to have? Well, if you put a control that
takes up the entire client area of your dialog template, you lose the docking functionality since
messages are dispatched to your control and not the dialog bar. By having a caption at the top you
will always have a place to 'grip' onto for your docking support. The new CDialogBar class,
CGripDialogBar, is derived from my CInitDialog class. An article on this control can be found on
this site, look for CInitDialogBar: A CDialogBar with OnInitDialog() and DDX Support. If you don't
find it you can always check out my site http://avenger.mri.psu.edu/ntpage.html. The first thing
to do in deriving the new class is to override the OnInitDialogBar() function so we can add the new
features for CGripDialogBar. We want a caption bar up at the top, to add this simply call the
following in your new OnInitDialogBar():
<FONT COLOR="#990000"><TT><PRE>
// Add our caption
ModifyStyle(0, WS_CAPTION);
</tt></PRE></FONT>
At this point if you derive a CGripDialogBar object you will see that this one statement of code,
does a lot for us. It creates a dialog bar that has a default windows caption. At this point the
real work begins, as we want to override the ugly windows deactivated caption bar and add our own
with grip bars that look like DevStudio抯. We also, will give it a color gradient so we will be
one up on DevStudio. In order to draw your own caption bar, you need to provide your own support
for several of the WM_NC??? messages. The painting itself is done in WM_NCPAINT. Add this point,
add a message handler for this function:
<FONT COLOR="#990000"><TT><PRE>
//{{AFX_MSG(CInitDialogBar)
afx_msg void OnNcPaint();
//{{AFX_MESSAGE
BEGIN_MESSAGE_MAP(CGripDialogBar, CInitDialogBar)
//{{AFX_MSG_MAP(CInitDialogBar)
ON_WM_NCPAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CGripDialogBar::OnNcPaint()
{
// Let MFC draw the frame for us
// We could do it put it's a pain
// since we do not change the default
// look
Default();
// Here we will paint our own caption
// bar for our dock window
CWindowDC dc(this);
CBrush Brush;
Brush.Attach((HBRUSH) GetStockObject(LTGRAY_BRUSH));
CRect rc;
GetWindowRect(rc);
// Rect of caption and X/Y Frames
CRect rc2(0,0, rc.Width(),
GetSystemMetrics(SM_CYCAPTION)
+ GetSystemMetrics(SM_CYFRAME));
//Get Caption Rect
CRect capRect;
capRect.left = rc2.left + GetSystemMetrics(SM_CXBORDER);
capRect.top = GetSystemMetrics(SM_CYFRAME);
capRect.right = rc2.right - GetSystemMetrics(SM_CXBORDER);
capRect.bottom = GetSystemMetrics( SM_CYSIZE );
dc.FillRect(rc2, &Brush);
float gradient = 0;
float startcolor = 100;
float endcolor = 220;
// calculate the slope for color gradient
gradient = (endcolor - startcolor) / rc.Width();
// Draw Color gradient
for(int i = 0; i < rc.Width(); i++)
{
int r, g, b;
float fr, fg, fb;
CPen* oldPen;
// Higer precision use floats for calcs
// Leads to smoother gradient
fr = gradient * (float) i + startcolor;
fg = gradient * (float) i + startcolor;
fb = gradient * (float) i + startcolor;
r = (int) fr;
g = (int) fg;
b = (int) fb;
CPen pen(PS_SOLID, 1, RGB(r,g,b));
dc.MoveTo(i,0);
oldPen = dc.SelectObject(&pen);
dc.LineTo(i,rc2.bottom);
dc.SelectObject(oldPen);
}
// Draw the docking grippers
CRect rect(5,7,(5+rc.Width()) - 30, 7+3);
dc.Draw3dRect(rect,
RGB(255,255,255),
RGB(128,128,128));
CRect rect2(5,11,(5+rc.Width()) - 30, 11+3);
dc.Draw3dRect(rect2,
RGB(255,255,255),
RGB(128,128,128));
// Adjust capRect to receive
// the close button
capRect.left = capRect.right - 20;
capRect.right -= 5;
// Put the close button on the caption
dc.DrawFrameControl(capRect,
DFC_CAPTION,
DFCS_CAPTIONCLOSE);
}
</tt></PRE></FONT>
Now, we have a control that has a caption that looks the way we want it to look.
The next step is to provide the docking control to the caption. If you have derived
an object at this point; Test it! Look how clicking on the caption does not cause the
caption to start the dock drag nor does double clicking dock / undock the control. By
overriding two more of WM_NC?? messages we can provide these functions quite easily.
The messages we need to override are WM_NCLBUTTONDOWN, and WM_NC_LBUTTONDBLCLK:
<FONT COLOR="#990000"><TT><PRE>
void CGripDialogBar::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
ASSERT(m_pDockContext != NULL);
switch(nHitTest)
{
case HTCAPTION:
{
m_pDockContext->StartDrag(point);
}
break;
default:
Default();
break;
}
}
void CGripDialogBar::OnNcLButtonDblClk(UINT nHitTest, CPoint point)
{
ASSERT(m_pDockContext != NULL);
// start the drag
m_pDockContext->ToggleDocking();
}
</tt></PRE></FONT>
Now if you derive an object and use it you will see that the docking support now works but has a
major flaw. When the window is in the floating state the caption does not disappear. We get
something that looks like this:
<p><img src="devstudio_like_controlbar2.gif"></p>
So now we need to look at the best way to remove or hide the caption when the window is floating.
You might think it is a simple matter of calling ModifyStyle(WS_CAPTION, 0); when the window is
floating. This however does not work. Although, the caption does get removed from the window, i.e.
mouse buttons no longer work in the caption, the window still draws the non-client area of the window.
And, also is you were to call ModifyStyle(0, WS_CAPTION); the caption does not reactivate itself.
There is a way, however, we can effectively hide the control from view; we will use this method.
The first step is to declare a RecalcLayout function in our class:
<FONT COLOR="#990000"><TT><PRE>
protected:
void RecalcLayout();
</tt></PRE></FONT>
We will call this function before we do our painting. If the window is in a floating state then
we move the control with respect to its parent up the height of the caption bar. The hides the
control bar抯 caption underneath the caption of the floating window. Implement the RecalcLayout
function like this:
<FONT COLOR="#990000"><TT><PRE>
void CGripDialogBar::RecalcLayout()
{
// If we are floating we do not want
// our new caption to be visible,
// so we move our window up so our
// caption is underneath the CMiniFrameWnd
// caption
if(IsFloating())
{
CRect rect;
GetWindowRect(rect);
SetWindowPos(NULL,
0,
-(GetSystemMetrics(SM_CYCAPTION)
+ GetSystemMetrics(SM_CYFRAME)),
rect.Width(),
rect.Height(),
NULL);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?