VC++日记(非模态,自定义消息,窗体移动……)
2011年07月07日
[b]1[/b][b]:如何做非模态对话框[/b][b][/b]
1)非模态对话框就是要控制对话框,不让它接管所有的消息循环。而DoModal()函数事实上就是“劫持”了所有的消息循环,只要它没有返回,任何“非该对话框消息”都会被忽略。事实上,如果我们避开使用DoModal(),我们就避免了这一层限制。我们重载对话窗的
[b]BOOL Create([/b][b]LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)[/b][b] [/b][b]函数,[/b]在用到该对话窗的时候,像创建任意一个CWnd一样,使用Creat来创建就可以了。当然,如果这样的话,很多数据成员的初始化工作就最好放到这里了。另:注意要调用基类的Creat函数,下面是重载Creat的一个实例:
[b]BOOL myDlg02::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) [/b]
[b]{[/b]
[b] // TODO: Add your specialized code here and/or call the base class[/b]
[b] m_bCapture = FALSE;[/b]
[b] CRect rect1;[/b]
[b] m_pview->GetWindowRect(rect1);[/b]
[b] m_pointToLeft = rect1.TopLeft();[/b]
[b] m_sizeOffset = CSize(0,0);[/b]
[b] return CDialog::Create(IDD, pParentWnd);[/b]
[b]}[/b]
2)使用非模态对话框时候,必须注意对话框跟视图类的“对话”。所以,我们往往提供一个Cview指针成员,用来和拥有该对话框的视图“沟通”。下面是一个例子:
[b]class myDlg02 : public CDialog[/b]
[b]{[/b]
[b]…[/b][b][/b]
[b]…[/b][b][/b]
[b]public:[/b]
[b] myDlg02(CWnd* pParent = NULL); // standard constructor[/b]
[b] myDlg02(CView* pview);[/b]
[b] myDlg02(){m_pview=NULL;}[/b]
[b] CSize m_sizeOffset;[/b]
[b] CPoint m_pointToLeft;[/b]
[b] BOOL m_bCapture;[/b]
[b] virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); [/b]
[b]protected:[/b]
[b]CView* m_pview;[/b][b][/b]
[b]…[/b][b][/b]
[b]…[/b][b][/b]
[b]}[/b]
同时呢,m_pview往往也是从对话框所发消息的目的地:
[b]void myDlg02::OnOK() [/b]
[b]{[/b]
[b] if (m_pview!=NULL)[/b]
[b] {[/b]
[b] UpdateData(TRUE);[/b]
[b] m_pview->PostMessage(WM_NICETOYOU,IDOK);[/b]
[b] }[/b]
[b] else[/b]
[b] CDialog::OnOK();[/b]
[b]}[/b]
[b] [/b]
[b]void myDlg02::OnCancel() [/b]
[b]{[/b][b][/b]
[b] if (m_pview!=NULL)[/b]
[b] m_pview->PostMessage(WM_GOODBYE,IDCANCEL);[/b][b][/b]
[b] else[/b][b][/b]
[b] CDialog::OnCancel();[/b][b][/b]
[b]}[/b][b][/b]
[b]上面的代码重载了[/b][b]OnOK[/b][b]和[/b][b]OnCancle[/b][b]函数,相当于控制了[/b][b]OK[/b][b],[/b][b]Cancle[/b][b]按钮的行为――让该对话框的拥有者来控制它们好了[/b][b]~~[/b]
[b]2[/b][b]:如何使用用户消息[/b][b][/b]
先明白一点:消息是发送出去了,那么由谁来处理呢?――自然是接收消息的“客户”了啊。所以,消息响应函数必须由客户负责。那么,用户自定义消息的消息响应函数的格式是怎样的呢?――
[b]afx_msg void OnmyDlgGBOK(WPARAM wParam,LPARAM lParam);[/b]
[b]afx_msg void OnmyDlgGBCancle(WPARAM wParam,LPARAM lParam);[/b]
[b](在视图类的头文件中声明之)[/b][b][/b]
[b]还要在消息映射表中添加:[/b][b][/b]
[b] ON_MESSAGE(WM_NICETOYOU,OnmyDlgGBOK)[/b]
[b] ON_MESSAGE(WM_GOODBYE,OnmyDlgGBCancle)[/b]
[b](在视图的[/b][b]CPP[/b][b]文件的消息映射表中添加)[/b][b][/b]
[b]其中[/b][b]WM_NICETOYOU [/b][b]、[/b][b]WM_GOODBYE[/b][b]是消息识别号。[/b][b][/b]
[b]这样,只要在必要的时候用视图的指针向视图发送消息,加上上面的链接,我们的消息响应函数就可以调用了。[/b][b][/b]
[b]另:介绍一下[/b]BOOL[b] PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )[/b]和[b] [/b][b][/b]
[b]LRESULT[/b][b] SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )[/b][b]这两个函数。首先,至于他们关于寄送和发送的区别就不谈了,关键要注意他们的参数。第一个参数是消息识别号,第二个和第三个参数是发给消息响应消息的参数,正好与消息响应函数的参数列表对应。WPARAM和LPARAM这两个类型其实际上是Long,也就是说,它们实质上是void指针,可以是任何类型的化身,可以根据实际情况灵活的运用它们。[/b]
3:如何动态控制窗体的位置和大小
[b]MoveWindow(CRect(m_pointToLeft,size),TRUE);[/b]
那么,如何向在标题栏上一样对整个对话框或者窗体进行动态移动呢?
{
[b]afx_msg void OnLButtonDown(UINT nFlags, CPoint point);[/b]
[b]afx_msg void OnLButtonUp(UINT nFlags, CPoint point);[/b]
[b]afx_msg void OnMouseMove(UINT nFlags, CPoint point);[/b]
[b]CSize m_sizeOffset;[/b]
[b]CPoint m_pointToLeft;[/b]
[b]BOOL m_bCapture;[/b]
[b]}[/b]
[b] [/b]
[b]{[/b]
[b]void myDlg02::OnLButtonDown(UINT nFlags, CPoint point) [/b]
[b]{[/b]
[b] // TODO: Add your message handler code here and/or call default[/b]
[b] ClientToScreen(&point);[/b]
[b] m_sizeOffset = point - m_pointToLeft;[/b]
[b] m_bCapture = TRUE;[/b]
[b] SetCapture();[/b]
[b] CDialog::OnLButtonDown(nFlags, point);[/b]
[b]}[/b]
[b] [/b]
[b]void myDlg02::OnLButtonUp(UINT nFlags, CPoint point) [/b]
[b]{[/b]
[b] // TODO: Add your message handler code here and/or call default[/b]
[b] m_bCapture = FALSE;[/b]
[b] ReleaseCapture();[/b]
[b] CDialog::OnLButtonUp(nFlags, point);[/b]
[b]}[/b]
[b] [/b]
[b]void myDlg02::OnMouseMove(UINT nFlags, CPoint point) [/b]
[b]{[/b]
[b] // TODO: Add your message handler code here and/or call default[/b]
[b] if (m_bCapture)[/b]
[b] { [/b]
[b] ClientToScreen(&point);[/b]
[b] m_pointToLeft = point - m_sizeOffset;[/b]
[b] CRect rect;[/b]
[b] GetWindowRect(rect);[/b]
[b] CSize size(rect.Width(),rect.Height());[/b]
[b] this->MoveWindow(CRect(m_pointToLeft,size),TRUE);[/b]
[b] CDialog::OnMouseMove(nFlags, point);[/b]
[b] }[/b]
[b]}[/b]
[b] BOOL myDlg02::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) [/b]
[b]{[/b]
[b] // TODO: Add your specialized code here and/or call the base class[/b]
[b] m_bCapture = FALSE;[/b]
[b] CRect rect1;[/b]
[b] m_pview->GetWindowRect(rect1);[/b]
[b] m_pointToLeft = rect1.TopLeft();[/b]
[b] m_sizeOffset = CSize(0,0);[/b]
[b] return CDialog::Create(IDD, pParentWnd);[/b]
[b]}[/b]
[b]}[/b]
不知道为什么,在做窗体的移动时候如果使用客户坐标,移动的窗体老是出现跳动和闪烁,而改成屏幕坐标,这个问题就神秘的解决了[b]。[/b][b][/b]
[b]4[/b][b]:如何控制窗体的初始化大小(最大,最小,默认)[/b][b][/b]
vc++ 窗口最大化方法
一般的做法是在 C**App::InitInstance()中,修改成这样:
[b]{[/b]
[b]//..[/b]
[b]…[/b][b][/b]
[b]m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
m_pMainWnd->UpdateWindow();
return TRUE;..[/b]
[b]}[/b]
或者,还在 CMainFrame::PreCreateWindow(CREATESTRUCT& cs)中,添加:
[b]{[/b]
[b]//...[/b]
[b]cs.style |= WS_MAXIMIZE;[/b]
[b]//...[/b]
[b]}[/b]
但是,这种方法的最大化会体现出窗体的有效变大的过程,这个是因为在ShowWindow之前,还有地方显示了窗体,做法是:
[b]CCommandLineInfo cmdInfo;[/b]
[b]ParseCommandLine(cmdInfo);[/b]
[b]// Dispatch commands specified on the command line[/b]
[b]//[/b][b]在[/b][b]ParseCommandLine[/b][b]之后,[/b][b]ProcessShellCommand[/b][b]之前,添加这句[/b][b]!!![/b]
[b]m_nCmdShow = SW_SHOWMAXIMIZED; [/b]
[b]if (!ProcessShellCommand(cmdInfo))
return FALSE;[/b]
[b]// The one and only window has been initialized, so show and update it.[/b]
[b]m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);[/b]
[b]m_pMainWnd->UpdateWindow();[/b]
[b]5[/b][b]:如何控制控件的层叠次序[/b][b][/b]
Ctrl+d,单击控件,会看到控件上的代号会变化,代号小的更底层。
2011年07月07日
[b]1[/b][b]:如何做非模态对话框[/b][b][/b]
1)非模态对话框就是要控制对话框,不让它接管所有的消息循环。而DoModal()函数事实上就是“劫持”了所有的消息循环,只要它没有返回,任何“非该对话框消息”都会被忽略。事实上,如果我们避开使用DoModal(),我们就避免了这一层限制。我们重载对话窗的
[b]BOOL Create([/b][b]LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)[/b][b] [/b][b]函数,[/b]在用到该对话窗的时候,像创建任意一个CWnd一样,使用Creat来创建就可以了。当然,如果这样的话,很多数据成员的初始化工作就最好放到这里了。另:注意要调用基类的Creat函数,下面是重载Creat的一个实例:
[b]BOOL myDlg02::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) [/b]
[b]{[/b]
[b] // TODO: Add your specialized code here and/or call the base class[/b]
[b] m_bCapture = FALSE;[/b]
[b] CRect rect1;[/b]
[b] m_pview->GetWindowRect(rect1);[/b]
[b] m_pointToLeft = rect1.TopLeft();[/b]
[b] m_sizeOffset = CSize(0,0);[/b]
[b] return CDialog::Create(IDD, pParentWnd);[/b]
[b]}[/b]
2)使用非模态对话框时候,必须注意对话框跟视图类的“对话”。所以,我们往往提供一个Cview指针成员,用来和拥有该对话框的视图“沟通”。下面是一个例子:
[b]class myDlg02 : public CDialog[/b]
[b]{[/b]
[b]…[/b][b][/b]
[b]…[/b][b][/b]
[b]public:[/b]
[b] myDlg02(CWnd* pParent = NULL); // standard constructor[/b]
[b] myDlg02(CView* pview);[/b]
[b] myDlg02(){m_pview=NULL;}[/b]
[b] CSize m_sizeOffset;[/b]
[b] CPoint m_pointToLeft;[/b]
[b] BOOL m_bCapture;[/b]
[b] virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); [/b]
[b]protected:[/b]
[b]CView* m_pview;[/b][b][/b]
[b]…[/b][b][/b]
[b]…[/b][b][/b]
[b]}[/b]
同时呢,m_pview往往也是从对话框所发消息的目的地:
[b]void myDlg02::OnOK() [/b]
[b]{[/b]
[b] if (m_pview!=NULL)[/b]
[b] {[/b]
[b] UpdateData(TRUE);[/b]
[b] m_pview->PostMessage(WM_NICETOYOU,IDOK);[/b]
[b] }[/b]
[b] else[/b]
[b] CDialog::OnOK();[/b]
[b]}[/b]
[b] [/b]
[b]void myDlg02::OnCancel() [/b]
[b]{[/b][b][/b]
[b] if (m_pview!=NULL)[/b]
[b] m_pview->PostMessage(WM_GOODBYE,IDCANCEL);[/b][b][/b]
[b] else[/b][b][/b]
[b] CDialog::OnCancel();[/b][b][/b]
[b]}[/b][b][/b]
[b]上面的代码重载了[/b][b]OnOK[/b][b]和[/b][b]OnCancle[/b][b]函数,相当于控制了[/b][b]OK[/b][b],[/b][b]Cancle[/b][b]按钮的行为――让该对话框的拥有者来控制它们好了[/b][b]~~[/b]
[b]2[/b][b]:如何使用用户消息[/b][b][/b]
先明白一点:消息是发送出去了,那么由谁来处理呢?――自然是接收消息的“客户”了啊。所以,消息响应函数必须由客户负责。那么,用户自定义消息的消息响应函数的格式是怎样的呢?――
[b]afx_msg void OnmyDlgGBOK(WPARAM wParam,LPARAM lParam);[/b]
[b]afx_msg void OnmyDlgGBCancle(WPARAM wParam,LPARAM lParam);[/b]
[b](在视图类的头文件中声明之)[/b][b][/b]
[b]还要在消息映射表中添加:[/b][b][/b]
[b] ON_MESSAGE(WM_NICETOYOU,OnmyDlgGBOK)[/b]
[b] ON_MESSAGE(WM_GOODBYE,OnmyDlgGBCancle)[/b]
[b](在视图的[/b][b]CPP[/b][b]文件的消息映射表中添加)[/b][b][/b]
[b]其中[/b][b]WM_NICETOYOU [/b][b]、[/b][b]WM_GOODBYE[/b][b]是消息识别号。[/b][b][/b]
[b]这样,只要在必要的时候用视图的指针向视图发送消息,加上上面的链接,我们的消息响应函数就可以调用了。[/b][b][/b]
[b]另:介绍一下[/b]BOOL[b] PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )[/b]和[b] [/b][b][/b]
[b]LRESULT[/b][b] SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )[/b][b]这两个函数。首先,至于他们关于寄送和发送的区别就不谈了,关键要注意他们的参数。第一个参数是消息识别号,第二个和第三个参数是发给消息响应消息的参数,正好与消息响应函数的参数列表对应。WPARAM和LPARAM这两个类型其实际上是Long,也就是说,它们实质上是void指针,可以是任何类型的化身,可以根据实际情况灵活的运用它们。[/b]
3:如何动态控制窗体的位置和大小
[b]MoveWindow(CRect(m_pointToLeft,size),TRUE);[/b]
那么,如何向在标题栏上一样对整个对话框或者窗体进行动态移动呢?
{
[b]afx_msg void OnLButtonDown(UINT nFlags, CPoint point);[/b]
[b]afx_msg void OnLButtonUp(UINT nFlags, CPoint point);[/b]
[b]afx_msg void OnMouseMove(UINT nFlags, CPoint point);[/b]
[b]CSize m_sizeOffset;[/b]
[b]CPoint m_pointToLeft;[/b]
[b]BOOL m_bCapture;[/b]
[b]}[/b]
[b] [/b]
[b]{[/b]
[b]void myDlg02::OnLButtonDown(UINT nFlags, CPoint point) [/b]
[b]{[/b]
[b] // TODO: Add your message handler code here and/or call default[/b]
[b] ClientToScreen(&point);[/b]
[b] m_sizeOffset = point - m_pointToLeft;[/b]
[b] m_bCapture = TRUE;[/b]
[b] SetCapture();[/b]
[b] CDialog::OnLButtonDown(nFlags, point);[/b]
[b]}[/b]
[b] [/b]
[b]void myDlg02::OnLButtonUp(UINT nFlags, CPoint point) [/b]
[b]{[/b]
[b] // TODO: Add your message handler code here and/or call default[/b]
[b] m_bCapture = FALSE;[/b]
[b] ReleaseCapture();[/b]
[b] CDialog::OnLButtonUp(nFlags, point);[/b]
[b]}[/b]
[b] [/b]
[b]void myDlg02::OnMouseMove(UINT nFlags, CPoint point) [/b]
[b]{[/b]
[b] // TODO: Add your message handler code here and/or call default[/b]
[b] if (m_bCapture)[/b]
[b] { [/b]
[b] ClientToScreen(&point);[/b]
[b] m_pointToLeft = point - m_sizeOffset;[/b]
[b] CRect rect;[/b]
[b] GetWindowRect(rect);[/b]
[b] CSize size(rect.Width(),rect.Height());[/b]
[b] this->MoveWindow(CRect(m_pointToLeft,size),TRUE);[/b]
[b] CDialog::OnMouseMove(nFlags, point);[/b]
[b] }[/b]
[b]}[/b]
[b] BOOL myDlg02::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) [/b]
[b]{[/b]
[b] // TODO: Add your specialized code here and/or call the base class[/b]
[b] m_bCapture = FALSE;[/b]
[b] CRect rect1;[/b]
[b] m_pview->GetWindowRect(rect1);[/b]
[b] m_pointToLeft = rect1.TopLeft();[/b]
[b] m_sizeOffset = CSize(0,0);[/b]
[b] return CDialog::Create(IDD, pParentWnd);[/b]
[b]}[/b]
[b]}[/b]
不知道为什么,在做窗体的移动时候如果使用客户坐标,移动的窗体老是出现跳动和闪烁,而改成屏幕坐标,这个问题就神秘的解决了[b]。[/b][b][/b]
[b]4[/b][b]:如何控制窗体的初始化大小(最大,最小,默认)[/b][b][/b]
vc++ 窗口最大化方法
一般的做法是在 C**App::InitInstance()中,修改成这样:
[b]{[/b]
[b]//..[/b]
[b]…[/b][b][/b]
[b]m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
m_pMainWnd->UpdateWindow();
return TRUE;..[/b]
[b]}[/b]
或者,还在 CMainFrame::PreCreateWindow(CREATESTRUCT& cs)中,添加:
[b]{[/b]
[b]//...[/b]
[b]cs.style |= WS_MAXIMIZE;[/b]
[b]//...[/b]
[b]}[/b]
但是,这种方法的最大化会体现出窗体的有效变大的过程,这个是因为在ShowWindow之前,还有地方显示了窗体,做法是:
[b]CCommandLineInfo cmdInfo;[/b]
[b]ParseCommandLine(cmdInfo);[/b]
[b]// Dispatch commands specified on the command line[/b]
[b]//[/b][b]在[/b][b]ParseCommandLine[/b][b]之后,[/b][b]ProcessShellCommand[/b][b]之前,添加这句[/b][b]!!![/b]
[b]m_nCmdShow = SW_SHOWMAXIMIZED; [/b]
[b]if (!ProcessShellCommand(cmdInfo))
return FALSE;[/b]
[b]// The one and only window has been initialized, so show and update it.[/b]
[b]m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);[/b]
[b]m_pMainWnd->UpdateWindow();[/b]
[b]5[/b][b]:如何控制控件的层叠次序[/b][b][/b]
Ctrl+d,单击控件,会看到控件上的代号会变化,代号小的更底层。