📄 wtl for mfc programmers, part vii.mht
字号:
window=20
classes. There are three classes, although you will normally only =
use one:=20
<CODE>CSplitterImpl</CODE>, <CODE>CSplitterWindowImpl</CODE>, and=20
<CODE>CSplitterWindowT</CODE>. The classes and their basic methods =
are=20
explained below.</P>
<H3><A name=3Dsplitclasses></A>Classes</H3>
<P><CODE>CSplitterImpl</CODE> is a template class that takes two =
template=20
parameters, a window interface class name and a boolean that =
indicates the=20
splitter orientation: <CODE><SPAN =
class=3Dcpp-keyword>true</SPAN></CODE> for=20
vertical, <CODE><SPAN class=3Dcpp-keyword>false</SPAN></CODE> for=20
horizontal. <CODE>CSplitterImpl</CODE> has almost all of the=20
implementation for a splitter, and many methods are overridable so =
you can=20
provide custom drawing of the split bar or other effects.=20
<CODE>CSplitterWindowImpl</CODE> derives from =
<CODE>CWindowImpl</CODE> and=20
<CODE>CSplitterImpl</CODE>, but doesn't have much code. It has an =
empty=20
<CODE>WM_ERASEBKGND</CODE> handler, and a <CODE>WM_SIZE</CODE> =
handler=20
that resizes the splitter window.</P>
<P>Finally, <CODE>CSplitterWindowT</CODE> derives from=20
<CODE>CSplitterImpl</CODE> and provides a window class name, =
<CODE><SPAN=20
class=3Dcpp-string>"WTL_SplitterWindow"</SPAN></CODE>. There are =
two=20
typedefs that you will normally use instead of the three above =
classes:=20
<CODE>CSplitterWindow</CODE> for a vertical splitter, and=20
<CODE>CHorSplitterWindow</CODE> for a horizontal splitter.</P>
<H3><A name=3Dcreatingsplitter></A>Creating a splitter</H3>
<P>Since <CODE>CSplitterWindow</CODE> derives from=20
<CODE>CWindowImpl</CODE>, you create a splitter just like any =
other child=20
window. Since the splitter will exist for the lifetime of the main =
frame,=20
you can add a <CODE>CSplitterWindow</CODE> member variable in=20
<CODE>CMainFrame</CODE>. In <CODE>CMainFrame::OnCreate()</CODE>, =
you=20
create the splitter as a child of the frame, then set the splitter =
as the=20
main frame's client window:</P><PRE>LRESULT CMainFrame::OnCreate ( =
LPCREATESTRUCT lpcs )
{
<SPAN class=3Dcpp-comment>// ...</SPAN>
<SPAN class=3Dcpp-keyword>const</SPAN> DWORD dwSplitStyle =3D WS_CHILD | =
WS_VISIBLE |=20
WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
dwSplitExStyle =3D WS_EX_CLIENTEDGE;
=20
m_wndSplit.Create ( *<SPAN class=3Dcpp-keyword>this</SPAN>, =
rcDefault, NULL,=20
dwSplitStyle, dwSplitExStyle );
=20
m_hWndClient =3D m_wndSplit;
}</PRE>
<P>After creating the splitter, you can assign windows to its =
panes, and=20
do any other necessary initialization.</P>
<H3><A name=3Dsplittermethods></A>Basic methods</H3><PRE><SPAN =
class=3Dcpp-keyword>bool</SPAN> SetSplitterPos(<SPAN =
class=3Dcpp-keyword>int</SPAN> xyPos =3D -<SPAN =
class=3Dcpp-literal>1</SPAN>, <SPAN class=3Dcpp-keyword>bool</SPAN> =
bUpdate =3D <SPAN class=3Dcpp-keyword>true</SPAN>)
<SPAN class=3Dcpp-keyword>int</SPAN> GetSplitterPos()</PRE>
<P>Call <CODE>SetSplitterPos()</CODE> to set the position of the =
splitter=20
bar. The position is expressed in pixels relative to the top edge =
(for=20
horizontal splitters) or left edge (for vertical splitters) of the =
splitter window. You can use the default of -1 to position the =
splitter=20
bar in the middle, making both panes the same size. You will =
usually pass=20
<CODE><SPAN class=3Dcpp-keyword>true</SPAN></CODE> for =
<CODE>bUpdate</CODE>,=20
to resize the two panes accordingly after moving the splitter bar. =
<CODE>GetSplitterPos()</CODE> returns the current position of the =
splitter=20
bar, relative to the top or left edge of the splitter =
window.</P><PRE><SPAN class=3Dcpp-keyword>bool</SPAN> =
SetSinglePaneMode(<SPAN class=3Dcpp-keyword>int</SPAN> nPane =3D =
SPLIT_PANE_NONE)
<SPAN class=3Dcpp-keyword>int</SPAN> GetSinglePaneMode()</PRE>
<P>Call <CODE>SetSinglePaneMode()</CODE> to change the splitter =
between=20
one-pane and two-pane mode. In one-pane mode, only one pane is =
visible and=20
the splitter bar is hidden, similar to how MFC dynamic splitters =
work=20
(although there is no little gripper handle to re-split the =
splitter). The=20
allowable values for <CODE>nPane</CODE> are: =
<CODE>SPLIT_PANE_LEFT</CODE>,=20
<CODE>SPLIT_PANE_RIGHT</CODE>, <CODE>SPLIT_PANE_TOP</CODE>,=20
<CODE>SPLIT_PANE_BOTTOM</CODE>, and <CODE>SPLIT_PANE_NONE</CODE>. =
The=20
first four indicate which pane to show (for example, passing=20
<CODE>SPLIT_PANE_LEFT</CODE> shows the left-side pane and hides =
the=20
right-side pane). Passing <CODE>SPLIT_PANE_NONE</CODE> shows both =
panes.=20
<CODE>GetSinglePaneMode()</CODE> returns one of those five=20
<CODE>SPLIT_PANE_*</CODE> values indicating the current =
mode.</P><PRE>DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, =
DWORD dwMask =3D <SPAN class=3Dcpp-literal>0</SPAN>)
DWORD GetSplitterExtendedStyle()</PRE>
<P>Splitter windows have their own style bits that control how the =
splitter bar moves when the entire splitter window is resized. The =
available styles are:</P>
<UL>
<LI><CODE>SPLIT_PROPORTIONAL</CODE>: Both panes in the splitter =
resize=20
together=20
<LI><CODE>SPLIT_RIGHTALIGNED</CODE>: The right pane stays the =
same size=20
when the entire splitter is resized, and the left pane resizes=20
<LI><CODE>SPLIT_BOTTOMALIGNED</CODE>: The bottom pane stays the =
same=20
size when the entire splitter is resized, and the top pane =
resizes=20
</LI></UL>
<P>If neither <CODE>SPLIT_PROPORTIONAL</CODE> nor=20
<CODE>SPLIT_RIGHTALIGNED</CODE>/<CODE>SPLIT_BOTTOMALIGNED</CODE> =
is=20
specified, the splitter becomes left- or top-aligned. If you pass=20
<CODE>SPLIT_PROPORTIONAL</CODE> and=20
<CODE>SPLIT_RIGHTALIGNED</CODE>/<CODE>SPLIT_BOTTOMALIGNED</CODE> =
together,=20
<CODE>SPLIT_PROPORTIONAL</CODE> takes precedence.</P>
<P>There is one additional style that controls whether the user =
can move=20
the splitter bar:</P>
<UL>
<LI><CODE>SPLIT_NONINTERACTIVE</CODE>: The splitter bar cannot =
be moved=20
and does not respond to the mouse </LI></UL>
<P>The default value of the extended styles is=20
<CODE>SPLIT_PROPORTIONAL</CODE>.</P><PRE><SPAN =
class=3Dcpp-keyword>bool</SPAN> SetSplitterPane(<SPAN =
class=3Dcpp-keyword>int</SPAN> nPane, HWND hWnd, <SPAN =
class=3Dcpp-keyword>bool</SPAN> bUpdate =3D <SPAN =
class=3Dcpp-keyword>true</SPAN>)
<SPAN class=3Dcpp-keyword>void</SPAN> SetSplitterPanes(HWND hWndLeftTop, =
HWND hWndRightBottom, <SPAN class=3Dcpp-keyword>bool</SPAN> bUpdate =3D =
<SPAN class=3Dcpp-keyword>true</SPAN>)
HWND GetSplitterPane(<SPAN class=3Dcpp-keyword>int</SPAN> nPane)</PRE>
<P>Call <CODE>SetSplitterPane()</CODE> to assign a child window to =
one=20
pane of the splitter. <CODE>nPane</CODE> is one of the=20
<CODE>SPLIT_PANE_*</CODE> values indicating which pane you are =
setting.=20
<CODE>hWnd</CODE> is the window handle of the child window. You =
can assign=20
child windows to both panes at once with =
<CODE>SetSplitterPanes()</CODE>.=20
You will usually take the default value of <CODE>bUpdate</CODE>, =
which=20
tells the splitter to immediately resize the child windows to fit =
in the=20
panes. You can get the <CODE>HWND</CODE> of the window in a pane =
with=20
<CODE>GetSplitterPane()</CODE>. If no window has been assigned to =
a pane,=20
<CODE>GetSplitterPane()</CODE> returns NULL.</P><PRE><SPAN =
class=3Dcpp-keyword>bool</SPAN> SetActivePane(<SPAN =
class=3Dcpp-keyword>int</SPAN> nPane)
<SPAN class=3Dcpp-keyword>int</SPAN> GetActivePane()</PRE>
<P><CODE>SetActivePane()</CODE> sets the focus to one of the =
windows in=20
the splitter. <CODE>nPane</CODE> is one of the =
<CODE>SPLIT_PANE_*</CODE>=20
values indicating which pane you are setting as the active one. It =
also=20
sets the default active pane (explained below).=20
<CODE>GetActivePane()</CODE> checks the window with the focus, and =
if that=20
window is a pane window or a child of a pane window, returns a=20
<CODE>SPLIT_PANE_*</CODE> value indicating which pane. If the =
window with=20
the focus is not a child of a pane, <CODE>GetActivePane()</CODE> =
returns=20
<CODE>SPLIT_PANE_NONE</CODE>.</P><PRE><SPAN =
class=3Dcpp-keyword>bool</SPAN> ActivateNextPane(<SPAN =
class=3Dcpp-keyword>bool</SPAN> bNext =3D <SPAN =
class=3Dcpp-keyword>true</SPAN>)</PRE>
<P>If the splitter is in single-pane mode, the focus is set to the =
visible=20
pane. Otherwise, <CODE>ActivateNextPane()</CODE> checks the window =
with=20
the focus with <CODE>GetActivePane()</CODE>. If a pane (or child =
of a=20
pane) has the focus, the splitter sets the focus to the other =
pane.=20
Otherwise, <CODE>ActivateNextPane()</CODE> activates the left/top =
pane if=20
<CODE>bNext</CODE> is true, or the right/bottom pane if bNext is=20
false.</P><PRE><SPAN class=3Dcpp-keyword>bool</SPAN> =
SetDefaultActivePane(<SPAN class=3Dcpp-keyword>int</SPAN> nPane)
<SPAN class=3Dcpp-keyword>bool</SPAN> SetDefaultActivePane(HWND hWnd)
<SPAN class=3Dcpp-keyword>int</SPAN> GetDefaultActivePane()</PRE>
<P>Call <CODE>SetDefaultActivePane()</CODE> with either a=20
<CODE>SPLIT_PANE_*</CODE> value or window handle to set that pane =
as the=20
default active pane. If the splitter window itself gets the focus, =
via a=20
<CODE>SetFocus()</CODE> call, it in turn sets the focus to the =
default=20
active pane. <CODE>GetDefaultActivePane()</CODE> returns a=20
<CODE>SPLIT_PANE_*</CODE> value indicating the current default =
active=20
pane.</P><PRE><SPAN class=3Dcpp-keyword>void</SPAN> =
GetSystemSettings(<SPAN class=3Dcpp-keyword>bool</SPAN> bUpdate)</PRE>
<P><CODE>GetSystemSettings()</CODE> reads various system settings =
and sets=20
data members accordingly. The splitter calls this automatically in =
<CODE>OnCreate()</CODE>, so you don't have to call it yourself. =
However,=20
your main frame should handle the <CODE>WM_SETTINGCHANGE</CODE> =
message=20
and pass it along to the frame; <CODE>CSplitterWindow</CODE> calls =
<CODE>GetSystemSettings()</CODE> in its =
<CODE>WM_SETTINGCHANGE</CODE>=20
handler. Pass true for <CODE>bUpdate</CODE> to have the splitter =
redraw=20
itself using the new settings.</P>
<H3><A name=3Dsplitdata></A>Data members</H3>
<P>Some other splitter features are controlled by setting public =
members=20
of <CODE>CSplitterWindow</CODE>. These are all reset when=20
<CODE>GetSystemSettings()</CODE> is called.</P>
<P><CODE>m_cxySplitBar</CODE>: Controls the width (for vertical =
splitters)=20
or height (for horizontal splitters) of the splitter bar. The =
default is=20
the value returned by =
<CODE>GetSystemMetrics(SM_CXSIZEFRAME)</CODE> (for=20
vertical splitters) or =
<CODE>GetSystemMetrics(SM_CYSIZEFRAME)</CODE> (for=20
horizontal splitters).</P>
<P><CODE>m_cxyMin</CODE>: Controls the minimum width (for vertical =
splitters) or height (for horizontal splitters) of each pane. The =
splitter=20
will not allow you to drag the bar if it would make either pane =
smaller=20
than this number of pixels. The default is 0 if the splitter =
window has=20
the <CODE>WS_EX_CLIENTEDGE</CODE> extended style. Otherwise, the =
default=20
is <CODE><SPAN=20
class=3Dcpp-literal>2</SPAN>*GetSystemMetrics(SM_CXEDGE)</CODE> =
(for=20
vertical splitters) or <CODE><SPAN=20
class=3Dcpp-literal>2</SPAN>*GetSystemMetrics(SM_CYEDGE)</CODE> =
(for=20
horizontal splitters).</P>
<P><CODE>m_cxyBarEdge</CODE>: Controls the width (for vertical =
splitters)=20
or height (for horizontal splitters) of the 3D edge drawn on the =
sides of=20
the splitter bar. The default value is the opposite of the default =
of=20
<CODE>m_cxyMin</CODE>.</P>
<P><CODE>m_bFullDrag</CODE>: If true, the panes resize as the =
splitter bar=20
is dragged. If false, only a ghost image of the splitter bar is =
drawn, and=20
the panes don't resize until the user releases the splitter bar. =
The=20
default is the value returned by=20
<CODE>SystemParametersInfo(SPI_GETDRAGFULLWINDOWS)</CODE>.=20
<H2><A name=3Dstartsample></A>Starting the Sample Project</H2>
<P>Now that we have the basics out of the way, let's see how to =
set up a=20
frame window that contains a splitter. Start a new project with =
the WTL=20
AppWizard. On the first page, leave <I>SDI Application</I> =
selected and=20
click Next. On the second page, uncheck <I>Toolbar</I>, then =
uncheck=20
<I>Use a view window</I> as shown here:</P>
<P><IMG height=3D387 alt=3D" [AppWizard pg 2 - 22K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC7/appwiz.png" =
width=3D477=20
align=3Dbottom border=3D0></P>
<P>We don't need a view window because the splitter and its panes =
will=20
become the "view." In <CODE>CMainFrame</CODE>, add a=20
<CODE>CSplitterWindow</CODE> member:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CMainFrame : <SPAN =
class=3Dcpp-keyword>public</SPAN> ...
{
<SPAN class=3Dcpp-comment>//...</SPAN>
<SPAN class=3Dcpp-keyword>protected</SPAN>:
CSplitterWindow m_wndVertSplit;
};</PRE>
<P>Then in <CODE>OnCreate()</CODE>, create the splitter and set it =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -