MFC控件积累——CDialog

来源:互联网 发布:淘宝刷钻全托 编辑:程序博客网 时间:2024/05/17 22:37

1.对于OnInitDialog是对WM_INITDIALOG消息的自动响应进行调用的,重载时在其中应该如下写:

声明:

virtual BOOL OnInitDialog();//This method is called in response to the WM_INITDIALOG message. 

定义:

BOOL ConnectConfigServerTab::OnInitDialog()
{
CDialog::OnInitDialog();/* 基类的OnInitDialog会调用一次UpdateData(FALSE) */


InitControls();


UpdateData(FALSE);/* 如果InitControls中对关联变量有更改,则会更新到界面上 */


return TRUE;
}


2.对话框中常用到“确定”和“取消”按钮,可以将对话框中任意的按钮ID设置为IDOK来响应OnOK()消息响应,设置为IDCANCEL来调用OnCancel()消息响应。要注意的是OnCancel()消息调用在用“X”关闭对话框时同样调用OnCancel()消息响应。


3.对话框是MFC中常用的窗口之一,而MFC对话框的默认的样式在很多应用中都显得很单调,如何对对话框的样式和风格进行修改是很多开发者需要面临的问题,本文从MFC的CDialog派生出自己的对话框样式,给出了很多改变对话框样式的函数,通过调用这些函数,就可以很好的改变对话框的各种风格。

主要的函数有:

//设置背景刷

void SetDlgBKBrushCBrushpBrush );

//设置背景颜色

void SetDlgBKColorCOLORREF clrBk );

//设置对话框字体

void SetFontCFontpFont );

//这只标题栏文字的位置,CAPTIONTEXT_LEFT,CAPTIONTEXT_CENTER,CAPTIONTEXT_RIGHT

void SetCaptinTextPosition(int positionType);

//设置标题文字的颜色,激活状态,非激活状态

void SetCaptionTextColor(COLORREF clrActiveCaptionText,COLORREF clrInactiveCaptionText);

//设置标题栏颜色,激活和非激活状态

void SetCaptionBarColor(COLORREF clrActiveCaptionBar,COLORREF clrInactiveCaptionBar);

//设置边框的位图,参数为各个边框图的路径

BOOL SetBorderBmp(LPCTSTR lpbmpLeft,LPCTSTR lpbmpRight,LPCTSTR lpbmpBottom)

//设置边框的位图,参数为各个边框图的句柄

BOOL SetBorderBmp(HBITMAP hbmpLeft,HBITMAP hbmpRight,HBITMAP hbmpBottom)

//设置标题栏上各个按钮的位图,给出路径

BOOL SetCaptionBtnBmp(CStringArraystrArrBtnClose,CStringArraystrArrBtnMin,CStringArraystrArrBtnMax)

//设置标题栏上各个按钮的位图,给出位图句柄指针

BOOL SetCaptionBtnBmp(HBITMAPhbmpBtnClose,HBITMAPhbmpBtnMin,HBITMAPhbmpBtnMaxint nElement)

//设置标题栏的位图,给出位图句柄

BOOL SetCaptionBmp(HBITMAP hbmpACaption,HBITMAP hbmpNCaption)

//设置标题栏的位图,给出位图路径

BOOL SetCaptionBmp(LPCTSTR lpszACaption,LPCTSTR lpszNCaption)

//设置对话框的各边界的颜色

void    SetBorderColor(COLORREF clrLeft,COLORREF clrTop,COLORREF clrRightCOLORREF clrBottom);

从上面可以看出,主要包括有:修改对话框的背景颜色,标题栏的颜色,标题栏的位图,标题栏字体的位置和颜色,包括激活和非激活状态,对话框边界的颜色,对话框字体等。


4.注意使用模态对话框(DoModal()来显示对话框)时如果对话框是new出来的,则在DoModal结束后应该释放掉对话框对象,因为如果对象再次调用DoModal会造成内存泄露。

同样对于非模态对话框,不能重复调用Create来创建对话框,同样会造成内存泄露。

5.对于模态对话框,不会产生BUG的用法是用局部变量的对话框对象,这样在DoModal结束后对象就析构了,在下次再次显示对话框时使用新的局部变量,这样不会造成对话框初始化中的种种问题。但有些情况下我们希望保留对话框的指针,通过一些其他函数中的操作修改对话框内容的话,就可能用动态创建(new())的方法创建一个用类的成员变量保存的对话框对象,但这时应该注意,在多次调用对话框的过程中,最好保证这个对话框对象都是新创建的,因为我们在上次调用DoModal()后对话框的成员变量在OnInitDialog()中被初始化了,而再次调用OnInitDialog()中使用CDialog::OnInitDialog()就会出错。

6.对于5中提到的情形,还有一点要注意,就是在对话框被DoModal显示而没有返回前,不应该delete或者说释放对话框对象的内存,否则程序跑飞。


7.今天遇到一个让对话框上"X"关闭按钮无效的需求,想到如下几种方法,记录下:

(1)刚开始是希望通过在OnInitDialog中根据需求修改对话框属性的方法:

if(不显示"X")

{

this->ModifyStyle(WS_SYSMENU,/* 移除系统菜单属性 */

0);

}

这种方式虽能实现功能,但"X"按钮直接消失了,并且会使对话框的图标、最大化和最小化按钮也消失了。

(2)希望通过重载CWnd::PreCreateWindow()函数在创建前就修改对话框属性:

事实证明这种想法是错误的,原因如下:

一般的窗口的创建是使用Create函数,这个函数在创建窗口之前调用了PreCreateWindow函数,并且允许在创建创建之前在PreCreateWindow注册一个拥有自定义窗口样式的新的窗口类,来创建一个拥有自定义类名新的窗口。而模式对话框是通过CreateDialogIndirect来创建的,在这当中并没有调用PreCreateWindow函数,重载的PreCreateWindow函数根本就不被执行,因此在这个函数里修改对话框的窗口类是没有用的。
  CDialog是通过CDialog::DoModal()函数创建窗口的,下面是MFC中DoModal函数的代码: 
  int CDialog::DoModal()
  {
   // 载入资源
   LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
   HGLOBAL hDialogTemplate = m_hDialogTemplate;
   HINSTANCE hInst = AfxGetResourceHandle();
   if (m_lpszTemplateName != NULL)
   {
   hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
   HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
   hDialogTemplate = LoadResource(hInst, hResource);
   }
   if (hDialogTemplate != NULL)
   lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);
   if (lpDialogTemplate == NULL)
   return -1;
   HWND hWndParent = PreModal();
   AfxUnhookWindowCreate();
   BOOL bEnableParent = FALSE;
   if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
   {
   ::EnableWindow(hWndParent, FALSE);
   bEnableParent = TRUE;
   }
   TRY
   {
   // 创建无模式对话框
   AfxHookWindowCreate(this);
   if (CreateDlgIndirect(lpDialogTemplate,
   CWnd::FromHandle(hWndParent), hInst))
   {
   if (m_nFlags & WF_CONTINUEMODAL)
   {
   // 进入模式循环
   DWORD dwFlags = MLF_SHOWONIDLE;
   if (GetStyle() & DS_NOIDLEMSG)
   dwFlags |= MLF_NOIDLEMSG;
   VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
   }
   // hide the window before enabling the parent, etc.
   if (m_hWnd != NULL)
   SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
   SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
   }
   }
   CATCH_ALL(e)
   {
   ......
   }
   END_CATCH_ALL 
   if (bEnableParent)
   ::EnableWindow(hWndParent, TRUE);
   if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
   ::SetActiveWindow(hWndParent);
   // destroy modal window
   DestroyWindow();
   PostModal();
   // 解锁、释放资源
   if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)
   UnlockResource(hDialogTemplate);
   if (m_lpszTemplateName != NULL)
   FreeResource(hDialogTemplate);
   return m_nModalResult;
  }
  在这个函里先是载入了对话框资源,然后通过LockResource函数,使DLGTEMPLATE类型指针指向相关的内存,然后把这个指针作为参数传递给了CreateDlgIndirect函数(调用了::CreateDialogIndirect)。DLGTEMPLATE的定义如下:
  typedef struct { 
   DWORD style; 
   DWORD dwExtendedStyle; 
   WORD cdit; 
   short x; 
   short y; 
   short cx; 
   short cy; 
  } DLGTEMPLATE, *LPDLGTEMPLATE; 
  这个结构体保存着创建对话框需要的样式、位置等信息,在DoModal函数里它是通过对话框资源得到的,那对话框资源里一定有它需要的东西。下面是从rc文件中摘录的对话框的信息:
  IDD_AAAA_DIALOG DIALOGEX 0, 0, 320, 200
  STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
  EXSTYLE WS_EX_APPWINDOW
  CAPTION "aaaa"
  FONT 9, "宋体"
  BEGIN
   DEFPUSHBUTTON "确定",IDOK,260,10,50,14
   PUSHBUTTON "取消",IDCANCEL,260,23,50,14
   LTEXT "TODO: 在这里设置对话控制。",IDC_STATIC,50,90,200,8
  END
  第一行是对话框的位置信息,第二行是对话框的样式,第三行是扩展样式,它们的内容就是在对话框编辑器修改属性时得到的内容。
  重载PreCreateWindow的目的不外乎是想在其中修改默认的窗口类的样式信息,然后达到修改窗口样式的目的。而对话框能在资源编辑器里修改它的所有应有的样式,而这些样式在DoModal函数里能被读出来,并传递给CreateDialoagIndirect函数,创建对话框。
  由于不能在PreCreateWindow函数里注册新的窗口类,所有的MFC程序的对话框的类名都是相同的:#32770。

(3)第三种方法,可以使"X"按钮灰显:

CMenu* pSysMenu = GetSystemMenu(FALSE);/* 取系统菜单 */
int i = pSysMenu->GetMenuItemID(1) ;/* 得到"X"号所在菜单项 */
pSysMenu->EnableMenuItem(i,MF_DISABLED );/* 使灰显 */


8.对于对话框上的图标显示:

对话框上的图标需要自己添加,方法如下:

HICON m_hIcon = AfxGetApp()->LoacIcon(IDR_MAINFRAM);

this->SetIcon(m_hIcon,TRUE);/*设置大图标*/

this->SetIcon(m_hIcon,FALSE);/* 设置小图标 */

需要注意的是:(1)不设定图标则对话框不会显示图标,不会从父窗口继承;

(2)对话框边框使用Resizing时强制要求对话框具有图标,如果未设置则有一个空白图标。

0 0
原创粉丝点击