⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wtl for mfc programmers, part iii.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
      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>
      <P><CODE>CMainFrame::OnViewToolBar()</CODE> is also different. =
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) &amp; =
<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 + -