科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件MFC程序员的WTL指南之高级界面类

MFC程序员的WTL指南之高级界面类

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文将介绍一些新类实现高级界面特性新类:控件自画和自定外观控件

作者:lithe 来源:blog 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
对话框中控件的UI Updating

  对话框中的的UI updating控制比MFC中简单得多,在MFC中,你需要响应未公开的WM_KICKIDLE消息,处理这个消息并触发控件的updating,在WTL中,没有这个诡计,不过向导存在一个BUG,需要手工添加一行代码解决这个问题。

  首先需要记住的是对话框必须是无模式的,因为CUpdateUI需要在程序的消息循环控制下工作。如果对话框是模式的,系统处理消息循环,我们程序的空闲处理函数就不会被调用,由于CUpdateUI是在空闲时间工作的,所以没有空闲处理就没有UI updating。

  ControlMania2的对话框是非模式的,类定义的开始部分很像是一个框架窗口类:

class CMainDlg : public CDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>,
public CMessageFilter, public CIdleHandler
{
 public:
  enum { IDD = IDD_MAINDLG };

  virtual BOOL PreTranslateMessage(MSG* pMsg);
  virtual 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()
 //...
};

  注意CMainDlg类从CUpdateUI派生并含有一个update UI链。OnInitDialog()做了这些工作,这和前面介绍的框架窗口中的代码很相似:

// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);

UIAddChildWindowContainer(m_hWnd);

  只是这次我们不是调用UIAddToolbar()或UIAddStatusBar(),而是调用UIAddChildWindowContainer(),它告诉CUpdateUI我们的对话框含有需要updating的字窗口,只要看看OnIdle(),你会怀疑少了写什么:

BOOL CMainDlg::OnIdle()
{
 return FALSE;
}

  你可能猜想这里应该调用另一个CUpdateUI的方法做一些实在的updating工作,你是对的,应该是这样的,向导在OnIdle()中漏掉了一行代码,现在加上:

BOOL CMainDlg::OnIdle()
{
 UIUpdateChildWindows();
 return FALSE;
}

  为了演示UI updating,我们设定鼠标点击左边的位图按钮,使得右边的按钮变得可用或禁用。先在update UI链中添加一个消息入口,使用UPDUI_CHILDWINDOW标志表示此入口是子窗口类型:

BEGIN_UPDATE_UI_MAP(CMainDlg)
 UPDATE_ELEMENT(IDC_ALYSON_BMPBTN, UPDUI_CHILDWINDOW)
END_UPDATE_UI_MAP()

  在左边的按钮的单击事件处理中,我们调用UIEnable()来翻转另一个按钮的使能状态:

void CMainDlg::OnAlysonODBtn ( UINT uCode, int nID, HWND hwndCtrl )
{
 static bool s_bBtnEnabled = true;

 s_bBtnEnabled = !s_bBtnEnabled;
 UIEnable ( IDC_ALYSON_BMPBTN, s_bBtnEnabled );
}

  DDV

  WTL的对话框数据验证(DDV)比MFC简单一些,在MFC中你需要分别使用DDX(对话框数据交换)宏和DDV(对话框数据验证)宏,在WTL中只需一个宏就可以了,WTL包含基本的数据验证支持,在DDV链中可以使用三个宏:

  DDX_TEXT_LEN

  和DDX_TEXT一样,只是还要验证字符串的长度(不包含结尾的空字符)小于或等于限制长度。

  DDX_INT_RANGE and DDX_UINT_RANGE

  和DDX_INT,DDX_UINT一样,还加了对数字的最大最小值的验证。

  DDX_FLOAT_RANGE

  除了像DDX_FLOAT一样完成数据交换之外,还验证数字的最大最小值。

  ControlMania2有一个ID是IDC_FAV_SEASON的edit box,它和成员变量m_nSeason相关联。


  由于有效的值是1到7,所以使用这样的数据验证宏:

BEGIN_DDX_MAP(CMainDlg)
 //...
 DDX_INT_RANGE(IDC_FAV_SEASON, m_nSeason, 1, 7)
END_DDX_MAP()

  OnOK()调用DoDataExchange()获得season的数值,并验证是在1到7之间。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章