📄 wtl for mfc programmers, part vii.mht
字号:
Close button from the header.=20
<LI><CODE>PANECNT_VERTICAL</CODE>: Set this style to make the =
header=20
area vertical, along the left side of the container window. =
</LI></UL>
<P>The default value of the extended styles is 0, meaning a =
horizontal=20
container with a close button.</P><PRE>HWND SetClient(HWND =
hWndClient)
HWND GetClient()</PRE>
<P>Call <CODE>SetClient()</CODE> to assign a child window to the =
pane=20
container. This works similarly to the =
<CODE>SetSplitterPane()</CODE>=20
method in <CODE>CSplitterWindow</CODE>. <CODE>SetClient()</CODE> =
returns=20
the <CODE>HWND</CODE> of the old client window. Call=20
<CODE>GetClient()</CODE> to get the <CODE>HWND</CODE> of the =
current=20
client window.</P><PRE>BOOL SetTitle(LPCTSTR lpstrTitle)
BOOL GetTitle(LPTSTR lpstrTitle, <SPAN class=3Dcpp-keyword>int</SPAN> =
cchLength)
<SPAN class=3Dcpp-keyword>int</SPAN> GetTitleLength()</PRE>
<P>Call <CODE>SetTitle()</CODE> to change the text shown in the =
header=20
area of the container. Call <CODE>GetTitle()</CODE> to retrieve =
the=20
current header text, and call <CODE>GetTitleLength()</CODE> to get =
the=20
length in characters of the current header text (not including the =
null=20
terminator).</P><PRE>BOOL EnableCloseButton(BOOL bEnable)</PRE>
<P>If the pane container has a Close button, you can use=20
<CODE>EnableCloseButton()</CODE> to enable and disable it.</P>
<H3><A name=3Dpcinsplitter></A>Using a pane container in a =
splitter=20
window</H3>
<P>To demonstrate how to add a pane container to an existing =
splitter,=20
we'll add a container to the left pane of the ClipSpy splitter. =
Instead of=20
assigning the list control to the left pane, we assign the pane =
container.=20
The list is then assigned to the pane container. Here are the =
lines in=20
<CODE>CMainFrame::OnCreate()</CODE> to change to set up the pane=20
container.</P><PRE>LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT =
lpcs )
{
<SPAN class=3Dcpp-comment>//...</SPAN>
m_wndVertSplit.Create ( *<SPAN class=3Dcpp-keyword>this</SPAN>, =
rcDefault, NULL, dwSplitStyle, dwSplitExStyle );
=20
<B><SPAN class=3Dcpp-comment>// Create the pane container.</SPAN>
m_wndPaneContainer.Create ( m_wndVertSplit, IDS_LIST_HEADER );
=20
<SPAN class=3Dcpp-comment>// Create the left pane (list of clip =
formats)</SPAN>
m_wndFormatList.Create ( m_wndPaneContainer, rcDefault );
</B><SPAN class=3Dcpp-comment>//...<B></SPAN>
</B> <B><SPAN class=3Dcpp-comment>// Set up the splitter panes</SPAN>
m_wndPaneContainer.SetClient ( m_wndFormatList );
m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, =
m_wndDataViewer );</B></PRE>
<P>Notice that the parent of the list control is=20
<CODE>m_wndPaneContainer</CODE>. Also, =
<CODE>m_wndPaneContainer</CODE> is=20
set as the left pane of the splitter.</P>
<P>Here's what the modified left pane looks like. I've also =
changed the=20
border styles a bit, since the pane container draws its own 3D =
border=20
around the header area. This doesn't look perfect, so you =
sometimes may=20
have to experiment with the border styles until you get the exact =
look you=20
want. (Then of course, you need to re-test on XP where themes make =
it even=20
more "interesting" to get the right look.)</P>
<P><IMG height=3D280 alt=3D" [Pane container - 5K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC7/panecont.png" =
width=3D356=20
align=3Dbottom border=3D0></P>
<H3><A name=3Dpcclosebtn></A>The Close button and message =
handling</H3>
<P>When the user clicks the Close button, the pane container sends =
a=20
<CODE>WM_COMMAND</CODE> message to its parent, with a command ID =
of=20
<CODE>ID_PANE_CLOSE</CODE>. When you use the pane container in a =
splitter,=20
the usual course of action is to call =
<CODE>SetSinglePaneMode()</CODE> to=20
hide the splitter pane that has the pane container. (But remember =
to=20
provide a way for the user to show the pane again!)</P>
<P>The <CODE>CPaneContainer</CODE> message map also has the=20
<CODE>FORWARD_NOTIFICATIONS()</CODE> macro, just like=20
<CODE>CSplitterWindow</CODE>, so the container passes notification =
messages from its client window to its parent. In the case of =
ClipSpy,=20
there are two windows between the list control and the main frame =
(the=20
pane container and the splitter), but the=20
<CODE>FORWARD_NOTIFICATIONS()</CODE> macros ensure that all =
notifications=20
from the list arrive at the main frame.</P>
<H2><A name=3Dadvancedsplitter></A>Advanced Splitter Features</H2>
<P>In this section, I'll describe how to do some common advanced =
UI tricks=20
with WTL splitters.</P>
<H3><A name=3Dnested></A>Nested splitters</H3>
<P>If you plan on writing an email client, you'll probably end up =
using=20
nested splitters, one horizontal and one vertical. This is easy to =
do with=20
WTL splitters - you create one splitter as the child of the =
other.</P>
<P>To show this in action, we'll add a horizontal splitter to =
ClipSpy.=20
After adding a <CODE>CHorSplitterWindow</CODE> member called=20
<CODE>m_wndHorzSplitter</CODE>, we first create that splitter the =
same way=20
as we create <CODE>m_wndVertSplitter</CODE>. To make=20
<CODE>m_wndHorzSplitter</CODE> the topmost splitter.=20
<CODE>m_wndVertSplitter</CODE> is now created as a child of=20
<CODE>m_wndHorzSplitter</CODE>. Finally, <CODE>m_hWndClient</CODE> =
is set=20
to <CODE>m_wndHorzSplitter</CODE>, since that's the window that =
now=20
occupies the main frame's client area.</P><PRE>LRESULT =
CMainFrame::OnCreate()
{
<SPAN class=3Dcpp-comment>//...</SPAN>
<SPAN class=3Dcpp-comment>// Create the splitter windows.</SPAN>
<B>m_wndHorzSplit.Create ( *<SPAN class=3Dcpp-keyword>this</SPAN>, =
rcDefault, NULL,=20
dwSplitStyle, dwSplitExStyle );
=20
m_wndVertSplit.Create ( m_wndHorzSplit, rcDefault, NULL,=20
dwSplitStyle, dwSplitExStyle );</B>
<SPAN class=3Dcpp-comment>//...</SPAN>
<B> <SPAN class=3Dcpp-comment>// Set the horizontal splitter as the =
client area window.</SPAN>
m_hWndClient =3D m_wndHorzSplit;
<SPAN class=3Dcpp-comment>// Set up the splitter panes</SPAN>
m_wndPaneContainer.SetClient ( m_wndFormatList );
m_wndHorzSplit.SetSplitterPane ( SPLIT_PANE_TOP, m_wndVertSplit );
m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, =
m_wndDataViewer );
</B><SPAN class=3Dcpp-comment>//...</SPAN>
}</PRE>
<P>And here's what the result looks like:</P>
<P><IMG height=3D323 alt=3D" [Horz splitter w/empty pane - 5K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC7/emptyhsplit.png" =
width=3D388=20
align=3Dbottom border=3D0></P>
<H3><A name=3Daxinpane></A>Using ActiveX controls in a pane</H3>
<P>Hosting an ActiveX control in a splitter pane is similar to =
hosting a=20
control in a dialog. You create the control at runtime using=20
<CODE>CAxWindow</CODE> methods, then assign the =
<CODE>CAxWindow</CODE> to=20
a pane in the splitter. Here's how you would add a browser control =
to the=20
bottom pane of the horizontal splitter:</P><PRE> <B><SPAN =
class=3Dcpp-comment>// Create the bottom pane (browser)</SPAN>
CAxWindow wndIE;
<SPAN class=3Dcpp-keyword>const</SPAN> DWORD dwIEStyle =3D WS_CHILD | =
WS_VISIBLE | WS_CLIPCHILDREN |
WS_HSCROLL | WS_VSCROLL;
wndIE.Create ( m_wndHorzSplit, rcDefault,=20
_T(<SPAN =
class=3Dcpp-string>"http://www.codeproject.com"</SPAN>), dwIEStyle );
</B>
<SPAN class=3Dcpp-comment>// Set the horizontal splitter as the =
client area window.</SPAN>
m_hWndClient =3D m_wndHorzSplit;
<SPAN class=3Dcpp-comment>// Set up the splitter panes</SPAN>
m_wndPaneContainer.SetClient ( m_wndFormatList );
<B>m_wndHorzSplit.SetSplitterPanes ( m_wndVertSplit, wndIE );
</B> m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, =
m_wndDataViewer );</PRE>
<H3><A name=3Dspecialdraw></A>Special drawing</H3>
<P>If you want to provide a different appearance for the splitter =
bar, for=20
example to draw a texture on it, you can derive a class from=20
<CODE>CSplitterWindowImpl</CODE> and override=20
<CODE>DrawSplitterBar()</CODE>. If you just want to tweak the =
appearance,=20
you can copy the existing function in =
<CODE>CSplitterWindowImpl</CODE> and=20
make any little changes you want. Here's an example that paints a =
diagonal=20
hatch pattern in the bar.</P><PRE><SPAN =
class=3Dcpp-keyword>template</SPAN> <<SPAN =
class=3Dcpp-keyword>bool</SPAN> t_bVertical =3D <SPAN =
class=3Dcpp-keyword>true</SPAN>>
<SPAN class=3Dcpp-keyword>class</SPAN> CMySplitterWindowT :=20
<SPAN class=3Dcpp-keyword>public</SPAN> =
CSplitterWindowImpl<CMySplitterWindowT<t_bVertical>, =
t_bVertical>
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
DECLARE_WND_CLASS_EX(_T(<SPAN =
class=3Dcpp-string>"My_SplitterWindow"</SPAN>),=20
CS_DBLCLKS, COLOR_WINDOW)
=20
<SPAN class=3Dcpp-comment>// Overrideables</SPAN>
<SPAN class=3Dcpp-keyword>void</SPAN> DrawSplitterBar(CDCHandle dc)
{
RECT rect;
=20
<SPAN class=3Dcpp-keyword>if</SPAN> ( m_br.IsNull() )
m_br.CreateHatchBrush ( HS_DIAGCROSS,=20
t_bVertical ? RGB(<SPAN =
class=3Dcpp-literal>255</SPAN>,<SPAN class=3Dcpp-literal>0</SPAN>,<SPAN =
class=3Dcpp-literal>0</SPAN>)=20
: RGB(<SPAN =
class=3Dcpp-literal>0</SPAN>,<SPAN class=3Dcpp-literal>0</SPAN>,<SPAN =
class=3Dcpp-literal>255</SPAN>) );
=20
<SPAN class=3Dcpp-keyword>if</SPAN> ( GetSplitterBarRect ( =
&rect ) )
{
dc.FillRect ( &rect, m_br );
=20
<SPAN class=3Dcpp-comment>// draw 3D edge if needed</SPAN>
<SPAN class=3Dcpp-keyword>if</SPAN> ( (GetExStyle() & =
WS_EX_CLIENTEDGE) !=3D <SPAN class=3Dcpp-literal>0</SPAN>)
dc.DrawEdge(&rect, EDGE_RAISED,=20
t_bVertical ? (BF_LEFT | BF_RIGHT)=20
: (BF_TOP | BF_BOTTOM));
}
}
=20
<SPAN class=3Dcpp-keyword>protected</SPAN>:
CBrush m_br;
};
=20
<SPAN class=3Dcpp-keyword>typedef</SPAN> CMySplitterWindowT<<SPAN =
class=3Dcpp-keyword>true</SPAN>> CMySplitterWindow;
<SPAN class=3Dcpp-keyword>typedef</SPAN> CMySplitterWindowT<<SPAN =
class=3Dcpp-keyword>false</SPAN>> CMyHorSplitterWindow;</PRE>
<P>Here's the result (with the bars made wider so the effect is =
easier to=20
see):</P>
<P><IMG height=3D349 alt=3D" [custom drawn bars - 14K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC7/custombars.png" =
width=3D413=20
align=3Dbottom border=3D0></P>
<H2><A name=3Dpcoverrides></A>Special Drawing in Pane =
Containers</H2>
<P><CODE>CPaneContainer</CODE> has a few methods that you can =
override to=20
change the appearance of a pane container. You can derive a new =
class from=20
<CODE>CPaneContainerImpl</CODE> and override the methods you want, =
for=20
example:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> =
CMyPaneContainer :
<SPAN class=3Dcpp-keyword>public</SPAN> =
CPaneContainerImpl<CMyPaneContainer>
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
DECLARE_WND_CLASS_EX(_T(<SPAN =
class=3Dcpp-string>"My_PaneContainer"</SPAN>), <SPAN =
class=3Dcpp-literal>0</SPAN>, -<SPAN class=3Dcpp-literal>1</SPAN>)
<SPAN class=3Dcpp-comment>//... overrides here ...</SPAN>
};</PRE>
<P>Some of the more interesting methods are:</P><PRE><SPAN =
class=3Dcpp-keyword>void</SPAN> CalcSize()</PRE>
<P>The purpose of <CODE>CalcSize()</CODE> is simply to set=20
<CODE>m_cxyHeader</CODE>, which controls the width or height of =
the=20
container's header area. There is a bug in=20
<CODE>SetPaneContainerExtendedStyle()</CODE>, however, that =
results in a=20
derived class's <CODE>CalcSize()</CODE> not being called when the =
pane is=20
switched between horizontal and vertical modes. You can change the =
<CODE>CalcSize()</CODE> call to <CODE>pT->CalcSize()</CODE> to =
fix=20
this.</P><PRE>HFONT GetTitleFont()</PRE>
<P>This method returns an <CODE>HFONT</CODE>, which will be used =
to draw=20
the header text. The default is the value returned by=20
<CODE>GetStockObject(DEFAULT_GUI_FONT)</CODE>, which is MS Sans =
Serif. If=20
you want to use the more modern-looking Tahoma, you can override=20
<CODE>GetTitleFont()</CODE> and return a handle to a Tahoma font =
that you=20
create.</P><PRE>BOOL GetToolTipText(LPNMHDR lpnmh)</PRE>
<P>Override this method to provide tooltip text when the cursor =
hovers=20
over the Close button. This method is actually a handler for=20
<CODE>TTN_GETDISPINFO</CODE>, so you cast <CODE>lpnmh</CODE> to a=20
<CODE>NMTTDISPINFO*</CODE> and set the members of that struct =
accordingly.=20
Keep
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -