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

📄 wtl for mfc programmers, part v - advanced dialog ui classes - wtl.htm

📁 WT教程中文版 内有详细的介绍 包括各个方面
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<SPAN class=cpp-keyword>bool</SPAN> SetHyperLink(LPCTSTR lpstrLink)</font></PRE>
<P>获得或设置控件关联超链接的URL,如果不指定超链接URL,控件会使用显示的文字字符串作为URL。</P>
      
<H5><font color="#990000">Navigation</font></H5>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">bool</font></SPAN><font color="#0033FF"> Navigate()</font></PRE>
<P>导航到当前超链接的URL,该URL或者是由SetHyperLink()函数指定的URL,或者就是控件的窗口文字。</P>
      
<H5><font color="#990000">Tooltip management</font></H5>
      
<P>没有公开的方法设置工具提示,所以需要直接使用CToolTipCtrl成员m_tip。</P>
<p>下图显示的就是ControlMania2对话框中的超链接控件:</p>
<P><IMG height=324 alt=" [WTL hyperlink - 12K] " 
      src="images/hyperlink5.png" 
      width=305 align=bottom border=0></P>
      
<P>在OnInitDialog()函数中设置URL:</P>
<PRE>   <font color="#0033FF"> m_wndLink.SetHyperLink ( _T(<SPAN class=cpp-string>"http://www.codeproject.com/"</SPAN>) );</font></PRE>
<H2><A name=uiupdctrl></A><font color="#FFFF66">对话框中控件的UI Updating</font></H2>
      
<P>对话框中的的UI updating控制比MFC中简单得多,在MFC中,你需要响应未公开的WM_KICKIDLE消息,处理这个消息并触发控件的updating,在WTL中,没有这个诡计,不过向导存在一个BUG,需要手工添加一行代码解决这个问题。</P>
<p>首先需要记住的是对话框必须是无模式的,因为CUpdateUI需要在程序的消息循环控制下工作。如果对话框是模式的,系统处理消息循环,我们程序的空闲处理函数就不会被调用,由于CUpdateUI是在空闲时间工作的,所以没有空闲处理就没有UI 
  updating。</p>
<p>ControlMania2的对话框是非模式的,类定义的开始部分很像是一个框架窗口类:</p>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CMainDlg : <SPAN class=cpp-keyword>public</SPAN> CDialogImpl&lt;CMainDlg&gt;, <SPAN class=cpp-keyword>public</SPAN> CUpdateUI&lt;CMainDlg&gt;,
                 <SPAN class=cpp-keyword>public</SPAN> CMessageFilter, <SPAN class=cpp-keyword>public</SPAN> CIdleHandler
{
<SPAN class=cpp-keyword>public</SPAN>:
    <SPAN class=cpp-keyword>enum</SPAN> { IDD = IDD_MAINDLG };
 
    <SPAN class=cpp-keyword>virtual</SPAN> BOOL PreTranslateMessage(MSG* pMsg);
    <SPAN class=cpp-keyword>virtual</SPAN> BOOL OnIdle();
 
    BEGIN_MSG_MAP_EX(CMainDlg)
        MSG_WM_INITDIALOG(OnInitDialog)
        COMMAND_ID_HANDLER_EX(IDOK, OnOK)
        COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
        COMMAND_ID_HANDLER_EX(IDC_ALYSON_BTN, OnAlysonODBtn)
    END_MSG_MAP()
 
    BEGIN_UPDATE_UI_MAP(CMainDlg)
    END_UPDATE_UI_MAP()
<SPAN class=cpp-comment>//...</SPAN>
};</font></PRE>
      
<P>注意CMainDlg类从CUpdateUI派生并含有一个update UI链。OnInitDialog()做了这些工作,这和前面介绍的框架窗口中的代码很相似:</P>
<PRE>    <font color="#0033FF"><SPAN class=cpp-comment>// register object for message filtering and idle updates</SPAN>
    CMessageLoop* pLoop = _Module.GetMessageLoop();
    ATLASSERT(pLoop != NULL);
    pLoop-&gt;AddMessageFilter(<SPAN class=cpp-keyword>this</SPAN>);
    pLoop-&gt;AddIdleHandler(<SPAN class=cpp-keyword>this</SPAN>);
 
    UIAddChildWindowContainer(m_hWnd);</font></PRE>
      
<P>只是这次我们不是调用UIAddToolbar()或UIAddStatusBar(),而是调用UIAddChildWindowContainer(),它告诉CUpdateUI我们的对话框含有需要updating的字窗口,只要看看OnIdle(),你会怀疑少了写什么:</P>
<PRE><font color="#0033FF">BOOL CMainDlg::OnIdle()
{
    <SPAN class=cpp-keyword>return</SPAN> FALSE;
}</font></PRE>
      
<P>你可能猜想这里应该调用另一个CUpdateUI的方法做一些实在的updating工作,你是对的,应该是这样的,向导在OnIdle()中漏掉了一行代码,现在加上:</P>
<PRE><font color="#0033FF">BOOL CMainDlg::OnIdle()
{
    <B>UIUpdateChildWindows();</B>
    <SPAN class=cpp-keyword>return</SPAN> FALSE;
}</font></PRE>
      
<P>为了演示UI updating,我们设定鼠标点击左边的位图按钮,使得右边的按钮变得可用或禁用。先在update UI链中添加一个消息入口,使用UPDUI_CHILDWINDOW标志表示此入口是子窗口类型:</P>
<PRE><font color="#0033FF">    BEGIN_UPDATE_UI_MAP(CMainDlg)
        <B>UPDATE_ELEMENT(IDC_ALYSON_BMPBTN, UPDUI_CHILDWINDOW)</B>
    END_UPDATE_UI_MAP()</font></PRE>
      
<P>在左边的按钮的单击事件处理中,我们调用UIEnable()来翻转另一个按钮的使能状态:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> CMainDlg::OnAlysonODBtn ( UINT uCode, <SPAN class=cpp-keyword>int</SPAN> nID, HWND hwndCtrl )
{
<SPAN class=cpp-keyword>static</SPAN> <SPAN class=cpp-keyword>bool</SPAN> s_bBtnEnabled = <SPAN class=cpp-keyword>true</SPAN>;

    s_bBtnEnabled = !s_bBtnEnabled;
    UIEnable ( IDC_ALYSON_BMPBTN, s_bBtnEnabled );
}</font></PRE>
      
<H2><A name=ddv></A><font color="#FFFF66">DDV</font></H2>
      
<P>WTL的对话框数据验证(DDV)比MFC简单一些,在MFC中你需要分别使用DDX(对话框数据交换)宏和DDV(对话框数据验证)宏,在WTL中只需一个宏就可以了,WTL包含基本的数据验证支持,在DDV链中可以使用三个宏:</P>
      
<DL> 
  <DT><CODE>DDX_TEXT_LEN</CODE> 
  <DD>和DDX_TEXT一样,只是还要验证字符串的长度(不包含结尾的空字符)小于或等于限制长度。
  <DT><CODE>DDX_INT_RANGE</CODE> and <CODE>DDX_UINT_RANGE</CODE> 
  <DD>和DDX_INT,DDX_UINT一样,还加了对数字的最大最小值的验证。
  <DT><CODE>DDX_FLOAT_RANGE</CODE> 
  <DD>除了像DDX_FLOAT一样完成数据交换之外,还验证数字的最大最小值。</DD>
</DL>
      
<P>ControlMania2有一个ID是IDC_FAV_SEASON的edit box,它和成员变量m_nSeason相关联。</P>
      
<P><IMG height=429 alt=" [Season selector edit box - 13K] " 
      src="images/cm2_seasonedit5.png" 
      width=373 align=bottom border=0></P>
      
<P>由于有效的值是1到7,所以使用这样的数据验证宏:</P>
<PRE><font color="#0033FF">    BEGIN_DDX_MAP(CMainDlg)
    <SPAN class=cpp-comment>//...</SPAN>
        DDX_INT_RANGE(IDC_FAV_SEASON, m_nSeason, <SPAN class=cpp-literal>1</SPAN>, <SPAN class=cpp-literal>7</SPAN>)
    END_DDX_MAP()</font></PRE>
      
<P>OnOK()调用DoDataExchange()获得season的数值,并验证是在1到7之间。</P>
      <H3><A name=ddvfail></A><font color="#FFFF66">处理DDV验证失败</font></H3>
      
<P>如果控件的数据验证失败,CWinDataExchange会调用重载函数OnDataValidateError(),默认到处理是驱动PC喇叭发出声音,你可能想给出更友好的错误指示。OnDataValidateError()的函数原型是:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> OnDataValidateError ( UINT nCtrlID, BOOL bSave, _XData&amp; data );</font></PRE>
      
<P>_XData是一个WTL的内部数据结构,CWinDataExchange根据输入的数据和允许的数据范围填充这个数据结构。下面是这个数据结构的定义:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">struct</font></SPAN><font color="#0033FF"> _XData
{
    _XDataType nDataType;
    <SPAN class=cpp-keyword>union</SPAN>
    {
        _XTextData textData;
        _XIntData intData;
        _XFloatData floatData;
    };
};</font></PRE>
      
<P>nDataType指示联合中的三个成员那个是有意义的,nDataType 的取值可以是:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">enum</font></SPAN><font color="#0033FF"> _XDataType
{
    ddxDataNull = <SPAN class=cpp-literal>0</SPAN>,
    ddxDataText = <SPAN class=cpp-literal>1</SPAN>,
    ddxDataInt = <SPAN class=cpp-literal>2</SPAN>,
    ddxDataFloat = <SPAN class=cpp-literal>3</SPAN>,
    ddxDataDouble = <SPAN class=cpp-literal>4</SPAN>
};</font></PRE>
      
<P>在我们的例子中,nDataType的值是ddxDataInt,这表示_XData中的_XIntData成员是有效的,_XIntData是个简单的数据结构:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">struct</font></SPAN><font color="#0033FF"> _XIntData
{
    <SPAN class=cpp-keyword>long</SPAN> nVal;
    <SPAN class=cpp-keyword>long</SPAN> nMin;
    <SPAN class=cpp-keyword>long</SPAN> nMax;
};</font></PRE>
      
<P>我们重载OnDataValidateError()函数,显示错误信息并告诉用户允许的数值范围:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> CMainDlg::OnDataValidateError ( UINT nCtrlID, BOOL bSave, _XData&amp; data )
{
CString sMsg;
 
    sMsg.Format ( _T(<SPAN class=cpp-string>"Enter a number between %d and %d"</SPAN>),
                  data.intData.nMin, data.intData.nMax );
 
    MessageBox ( sMsg, _T(<SPAN class=cpp-string>"ControlMania2"</SPAN>), MB_ICONEXCLAMATION );
 
    ::SetFocus ( GetDlgItem(nCtrlID) );
}</font></PRE>
      
<P>_XData中的另外两个结构_XTextData和_XFloatData的定义在atlddx.h中,感兴趣的话可以打开这个文件查看一下。</P>
<h2><A name=resizing></A><font color="#FFFF66">改变对话框的大小</font></h2>
<P>WTL引起我的注意的第一件事是对可调整大小对话框的内建的支持。在这之前我曾写过一篇<a href="http://www.codeproject.com/wtl/wtldlgresize.asp">关于这个主题的文章</a>,详情请参考这篇文章。简单的说就是将CDialogResize类添加到对话框的集成列表,在OnInitDialog()中调用DlgResize_Init(),然后将消息链入CDialogResize。</P>
      <H2><A name=upnext></A><font color="#FFFF66">继续</font></H2>
      
<P>下一章,我将介绍如何在对话框中使用ActiveX控件和如何处理控件触发的事件。</P>
<H2><A name=references></A><font color="#FFFF66">参考</font></H2>
      <P><A href="http://www.codeproject.com/wtl/wtldlgresize.asp">Using WTL's 
      Built-in Dialog Resizing Class</A> - Michael Dunn</P>
      <P><A href="http://www.codeproject.com/wtl/propsheetddx.asp">Using DDX and 
      DDV with WTL</A> - Less Wright</P>
      
<H2><A name=revisionhistory></A><font color="#FFFF66">修改记录</font></H2>
<P>2003年4月28日,本文第一次发表。</P>

</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -