?? wtl for mfc programmers, part iii.mht
字號:
step is to add the <CODE>UPDUI_TOOLBAR</CODE> flag to each =
macro:</P><PRE>BEGIN_UPDATE_UI_MAP(CMainFrame)
UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP <B>| =
UPDUI_TOOLBAR</B>)
UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP <B>| =
UPDUI_TOOLBAR</B>)
END_UPDATE_UI_MAP()</PRE>
<P>There are two other functions to call to hook up toolbar button =
updating, but fortunately the AppWizard code already does them, so =
if you=20
build the project at this point, the menu items and toolbar =
buttons will=20
both be updated.</P>
<H3><A name=3Denabletbupdate></A>Enabling toolbar UI updating</H3>
<P>If you look in <CODE>CMainFrame::OnCreate()</CODE>, you'll see =
a new=20
block of code that sets up the initial state of the two =
<I>View</I> menu=20
items:</P><PRE>LRESULT CMainFrame::OnCreate( ... )
{
<SPAN class=3Dcpp-comment>// ...</SPAN>
m_hWndClient =3D m_view.Create(...);
=20
UIAddToolBar(m_hWndToolBar);
UISetCheck(ID_VIEW_TOOLBAR, <SPAN class=3Dcpp-literal>1</SPAN>);
UISetCheck(ID_VIEW_STATUS_BAR, <SPAN class=3Dcpp-literal>1</SPAN>);
<SPAN class=3Dcpp-comment>// ...</SPAN>
}</PRE>
<P><CODE>UIAddToolBar()</CODE> tells <CODE>CUpdateUI</CODE> the=20
<CODE>HWND</CODE> of our toolbar, so it knows what window to send =
messages=20
to when it needs to update the button states. The other important =
call is=20
in <CODE>OnIdle()</CODE>:</P><PRE>BOOL CMainFrame::OnIdle()
{
UIUpdateToolBar();
<SPAN class=3Dcpp-keyword>return</SPAN> FALSE;
}</PRE>
<P>Recall that <CODE>OnIdle()</CODE> is called by=20
<CODE>CMessageLoop::Run()</CODE> when it has no messages waiting =
in the=20
message queue. <CODE>UIUpdateToolBar()</CODE> goes through the =
update UI=20
map, looks for elements with the <CODE>UPDUI_TOOLBAR</CODE> flag =
that have=20
been changed with calls such as <CODE>UISetCheck()</CODE>, and =
changes the=20
state of the buttons accordingly. Note that we didn't need these =
two steps=20
when we were just updating popup menu items, because=20
<CODE>CUpdateUI</CODE> handles <CODE>WM_INITMENUPOPUP</CODE> and =
updates=20
the menu when that message is sent.</P>
<P>If you check out the sample project, it also shows how to UI =
update=20
top-level menu items in the frame's menu bar. There is an item =
that=20
executes the <I>Start</I> and <I>Stop</I> commands to start and =
stop the=20
clock. While this is not a common (or even recommended) thing to =
do --=20
items in the menu bar should always be popups -- I included it for =
the=20
sake of completeness in covering <CODE>CUpdateUI</CODE>. Look for =
the=20
calls to <CODE>UIAddMenuBar()</CODE> and=20
<CODE>UIUpdateMenuBar()</CODE>.</P>
<H2><A name=3Duserebar></A>Using a Rebar Instead of a Plain =
Toolbar</H2>
<P><CODE>CFrameWindowImpl</CODE> also supports using a rebar to =
give your=20
app a look similar to Internet Explorer. Using a rebar is also the =
way to=20
go if you need multiple toolbars. To use a rebar, check the Rebar =
box in=20
the second page of the AppWizard, as shown here:</P>
<P><IMG height=3D387 alt=3D" [AppWizard pg 2 with rebar checked - =
21K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC3/appwiz3.png" =
width=3D477=20
align=3Dbottom border=3D0></P>
<P>The second sample project, WTLClock3, was made with this option =
checked. If you're following along in the sample code, open =
WTLClock3=20
now.</P>
<P>The first thing you'll notice is that the code to create the =
toolbar is=20
different. This makes sense since we're using a rebar in this app. =
Here is=20
the relevant code:</P><PRE>LRESULT CMainFrame::OnCreate(...)
{
HWND hWndToolBar =3D CreateSimpleToolBarCtrl ( m_hWnd,=20
IDR_MAINFRAME, FALSE,=20
ATL_SIMPLE_TOOLBAR_PANE_STYLE );
=20
CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
AddSimpleReBarBand(hWndToolBar);
<SPAN class=3Dcpp-comment>// ...</SPAN>
}</PRE>
<P>It begins by creating a toolbar, but using a different style,=20
<CODE>ATL_SIMPLE_TOOLBAR_PANE_STYLE</CODE>. This is a #define in=20
atlframe.h that is similar to =
<CODE>ATL_SIMPLE_TOOLBAR_STYLE</CODE>, but=20
has additional styles such as <CODE>CCS_NOPARENTALIGN</CODE> that =
are=20
necessary for the toolbar to work properly as the child of the =
rebar.</P>
<P>The next line calls <CODE>CreateSimpleReBar()</CODE>, which =
creates a=20
rebar and stores its <CODE>HWND</CODE> in =
<CODE>m_hWndToolBar</CODE>.=20
Next, <CODE>AddSimpleReBarBand()</CODE> adds a band to the rebar, =
and=20
tells the rebar that the toolbar will be contained in that =
band.</P>
<P><IMG height=3D206 alt=3D" [App with rebar - 4K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC3/rebar.png" =
width=3D252=20
align=3Dbottom border=3D0></P>
Instead of=20
hiding <CODE>m_hWndToolBar</CODE> (that would hide the entire =
rebar, not=20
just the one toolbar), it hides the band that contains the =
toolbar.</P>
<P>If you want to have multiple toolbars, you can create them and =
call=20
<CODE>AddSimpleReBarBand()</CODE> in <CODE>OnCreate()</CODE> just =
like the=20
wizard-generated code does for the first toolbar. Since=20
<CODE>CFrameWindowImpl</CODE> uses the standard rebar control, =
there is no=20
support for dockable toolbars like in MFC; all the user can do is=20
rearrange the positions of the toolbars within the rebar.</P>
<H2><A name=3Dmultipanesb></A>Multi-Pane Status Bars</H2>
<P>WTL has another status bar class that implements a bar with =
multiple=20
panes, similar to the default MFC status bar that has CAPS LOCK =
and NUM=20
LOCK indicators. The class is =
<CODE>CMultiPaneStatusBarCtrl</CODE>, and is=20
demonstrated in the WTLClock3 sample project. This class supports =
limited=20
UI updating, as well as a "default" pane that stretches to the =
full width=20
of the bar to show flyby help when a popup menu is displayed.</P>
<P>The first step is to declare a =
<CODE>CMultiPaneStatusBarCtrl</CODE>=20
member variable in <CODE>CMainFrame</CODE>:</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>:
CMultiPaneStatusBarCtrl m_wndStatusBar;
};</PRE>
<P>Then in <CODE>OnCreate()</CODE>, we create the bar and set it =
up for UI=20
updating:</P><PRE> m_hWndStatusBar =3D m_wndStatusBar.Create ( =
*<SPAN class=3Dcpp-keyword>this</SPAN> );
UIAddStatusBar ( m_hWndStatusBar );</PRE>
<P>Notice that we store the status bar handle in=20
<CODE>m_hWndStatusBar</CODE>, just like=20
<CODE>CreateSimpleStatusBar()</CODE> would.</P>
<P>The next step is to set up the panes by calling=20
<CODE>CMultiPaneStatusBarCtrl::SetPanes()</CODE>:</P><PRE> BOOL =
SetPanes(<SPAN class=3Dcpp-keyword>int</SPAN>* pPanes, <SPAN =
class=3Dcpp-keyword>int</SPAN> nPanes, <SPAN =
class=3Dcpp-keyword>bool</SPAN> bSetText =3D <SPAN =
class=3Dcpp-keyword>true</SPAN>);</PRE>
<P>The parameters are:</P>
<DL>
<DT><CODE>pPanes</CODE>=20
<DD>An array of pane IDs=20
<DT><CODE>nPanes</CODE>=20
<DD>The number of elements in <CODE>pPanes</CODE>=20
<DT><CODE>bSetText</CODE>=20
<DD>If true, all panes have their text set immediately. This is=20
explained below. </DD></DL>
<P>The pane IDs can either be <CODE>ID_DEFAULT_PANE</CODE> to =
create the=20
flyby help pane, or IDs of strings in the string table. For the=20
non-default panes, WTL loads up the string and calculates its =
width, then=20
sets the corresponding pane to the same width. This is the same =
logic that=20
MFC uses.</P>
<P><CODE>bSetText</CODE> controls whether the panes show the =
strings=20
immediately. If it is set to true, <CODE>SetPanes()</CODE> shows =
the=20
strings in each pane, otherwise the panes are left blank.</P>
<P>Here's our call to <CODE>SetPanes()</CODE>:</P><PRE> <SPAN =
class=3Dcpp-comment>// Create the status bar panes.</SPAN>
<SPAN class=3Dcpp-keyword>int</SPAN> anPanes[] =3D { ID_DEFAULT_PANE, =
IDPANE_STATUS,=20
IDPANE_CAPS_INDICATOR };
=20
m_wndStatusBar.SetPanes ( anPanes, <SPAN =
class=3Dcpp-literal>3</SPAN>, <SPAN class=3Dcpp-keyword>false</SPAN> =
);</PRE>
<P>The string <CODE>IDPANE_STATUS</CODE> is "@@@@", which should=20
(hopefully) be enough space to show the two clock status strings =
"Running"=20
and "Stopped". Just as with MFC, you have to approximate how much =
space=20
you'll need for the pane. The string =
<CODE>IDPANE_CAPS_INDICATOR</CODE> is=20
"CAPS".</P>
<H3><A name=3Duiupdatesb></A>UI updating the panes</H3>
<P>In order for us to update the pane text, we'll need entries in =
the=20
update UI map:</P><PRE> BEGIN_UPDATE_UI_MAP(CMainFrame)
<SPAN class=3Dcpp-comment>//...</SPAN>
UPDATE_ELEMENT(<SPAN class=3Dcpp-literal>1</SPAN>, =
UPDUI_STATUSBAR) <SPAN class=3Dcpp-comment>// clock status</SPAN>
UPDATE_ELEMENT(<SPAN class=3Dcpp-literal>2</SPAN>, =
UPDUI_STATUSBAR) <SPAN class=3Dcpp-comment>// CAPS indicator</SPAN>
END_UPDATE_UI_MAP()</PRE>
<P>The first parameter in the macro is the <I>index</I> of the =
pane, not=20
its ID. This is unfortunate because if you rearrange the panes, =
you need=20
to remember to update the numbers in the map.</P>
<P>Since we pass false as the third parameter to =
<CODE>SetPanes()</CODE>,=20
the panes are initially empty. Our next step is to set the initial =
text of=20
the clock status pane to "Running".</P><PRE> <SPAN =
class=3Dcpp-comment>// Set the initial text for the clock status =
pane.</SPAN>
UISetText ( <SPAN class=3Dcpp-literal>1</SPAN>, _T(<SPAN =
class=3Dcpp-string>"Running"</SPAN>) );</PRE>
<P>Again, the first parameter is the index of the pane.=20
<CODE>UISetText()</CODE> is the only UI update call that works on =
status=20
bars.</P>
<P>Finally, we need to add a call to =
<CODE>UIUpdateStatusBar()</CODE> in=20
<CODE>CMainFrame::OnIdle()</CODE> so that the status bar panes are =
updated=20
at idle time:</P><PRE>BOOL CMainFrame::OnIdle()
{
UIUpdateToolBar();
<B>UIUpdateStatusBar();</B>
<SPAN class=3Dcpp-keyword>return</SPAN> FALSE;
}</PRE>
<P>There is a problem in <CODE>CUpdateUI</CODE> that appears when =
you use=20
<CODE>UIUpdateStatusBar()</CODE> - text in menu items is not =
updated after=20
you use <CODE>UISetText()</CODE>! If you look at the WTLClock3 =
project,=20
the clock start/stop menu item has been moved to a <I>Clock</I> =
menu, and=20
the handler for that command sets the menu item's text. However, =
if the=20
call to <CODE>UIUpdateStatusBar()</CODE> is present, the=20
<CODE>UISetText()</CODE> call does not take effect. I have not=20
investigated whether this can be fixed, so keep it in mind if you =
plan on=20
updating the text in menu items.</P>
<P>Finally, we need to check the state of the CAPS LOCK key and =
update=20
pane 2 accordingly. This code can go right in =
<CODE>OnIdle()</CODE>, so=20
the state will get checked every time the app goes =
idle.</P><PRE>BOOL CMainFrame::OnIdle()
{
<B><SPAN class=3Dcpp-comment>// Check the current Caps Lock state, =
and if it is on, show the</SPAN>
<SPAN class=3Dcpp-comment>// CAPS indicator in pane 2 of the status =
bar.</SPAN>
<SPAN class=3Dcpp-keyword>if</SPAN> ( GetKeyState(VK_CAPITAL) & =
<SPAN class=3Dcpp-literal>1</SPAN> )
UISetText ( <SPAN class=3Dcpp-literal>2</SPAN>, =
CString(LPCTSTR(IDPANE_CAPS_INDICATOR)) );
<SPAN class=3Dcpp-keyword>else</SPAN>
UISetText ( <SPAN class=3Dcpp-literal>2</SPAN>, _T(<SPAN =
class=3Dcpp-string>""</SPAN>) );</B>
=20
UIUpdateToolBar();
UIUpdateStatusBar();
<SPAN class=3Dcpp-keyword>return</SPAN> FALSE;
}</PRE>
<P>The first <CODE>UISetText()</CODE> call loads the "CAPS" string =
from=20
the string table using a neat (but fully documented) trick in the=20
<CODE>CString</CODE> constructor.</P>
<P>So after all that code, here's what the status bar looks =
like:</P>
<P><IMG height=3D218 alt=3D" [Multipane status bar - 4K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC3/multipanesb.png" =
width=3D265=20
align=3Dbottom border=3D0></P>
<H2><A name=3Dupnext></A>Up Next: All About Dialogs</H2>
<P>In Part IV, I'll cover dialogs (both the ATL classes and WTL=20
enhancements), control wrappers, and more WTL message handling=20
improvements that relate to dialogs and controls.</P>
<H2><A name=3Dreferences></A>References</H2>
<P><A =
href=3D"http://www.codeproject.com/wtl/multipanestatusbar.asp">"How to=20
use the WTL multipane status bar control"</A> by Ed Gadziemski =
goes into=20
more detail on the <CODE>CMultiPaneStatusBarCtrl</CODE> class.=20
<H2><A name=3Drevisionhistory></A>Revision History</H2>
<P>April 11, 2003: Article first published.=20
</P><!-- Article Ends --></DIV>
<H2>About Michael Dunn</H2>
<TABLE width=3D"100%" border=3D0>
<TBODY>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -