关闭

VC技术内幕笔记4-7

837人阅读 评论(0) 收藏 举报
 
第七章:无模式对话框 和 Windows通用对话框类

 

1,[无模式对话框]在它处于激活状态下还允许用户在(同一个应用程序中)其它地方工作。
   [通用对话框]则是C++和一组Windows的实用对话框之间的程序设计借口,包括File Open,Page Setup,Color等等,它们都是通过COMDLG32.DLL来实现的。

2,两种发送Windows消息:
CWnd::SendMessage//立刻导致对窗口控制函数的调用
CWnd::PostMessage//将消息放进Windows消息队列。对消息的处理可能被滞后。
具体:
1)LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );
//Sends the specified message to this window. The SendMessage member function calls the window procedure directly and does not return until that window procedure has processed the message. This is in contrast to the PostMessage member function, which places the message into the window’s message queue and returns immediately.

2)BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );
//Places a message in the window’s message queue and then returns without waiting for the corresponding window to process the message. Messages in a message queue are retrieved by calls to the GetMessage or PeekMessage Windows function.

3,对话框实际上应该属于应用程序的主框架窗口,而不属于视图。(对话框默认弹出特性)
(注:还未领悟,先留着。)

4,对话框窗口的创建和取消完全取决与用户的操作,而对话框对象则将直到应用程序被终止时才会被删除。
(除了主框架窗口之外,对于几乎所有的窗口类型,DestroyWindow函数都不会将C++对象删除掉。所以要注意手动添加删除对话框对象代码)

5,Windows 常量WM_USER是用户自定义消息中可以利用的第一个消息ID。
#define WM_USER       0x0400
//The WM_USER constant is used by applications to help define private messages, usually of the form WM_USER+X, where X is an integer value.
说明:
1)CWnd::PostMessage//发送消息。利用wParam , LPARAM可以向响应消息的处理函数传送附加数据信息。
BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );
2)在WIN32中,用wParam 和LPARAM参数来传递消息数据是最常用的手段(如:将鼠标的X,Y坐标压缩进lParam)。而在MFC库中,消息数据可以更多样的类型来传递(如:可以CPoint对象来传递鼠标信息)。
对于用户自定义消息,只能使用wParam 和LPARAM参数来传递消息附加数据信息。
3)案例说明:
在对话框类中:
#define WM_GOODBYE WM_USER + 5//定义自定义消息
m_pView->PostMessage(WM_GOODBYE, IDOK);//向View类发送WM_GOODBYE消息,附加消息IDOK存放在wParam 中。m_pView指向当前View类对象。
在View 类对象中
afx_msg LRESULT OnGoodbye(WPARAM wParam, LPARAM lParam);
ON_MESSAGE(WM_GOODBYE, OnGoodbye)
LRESULT CEx07aView::OnGoodbye(WPARAM wParam, LPARAM lParam)
{
 return 0L;
}
4)技巧:在对话框类中重载构造函数,参数为CView*指针。再在对话框类中定义一个CView*指针数据成员。这样,如果在View类中通过传入this指针来构造对话框对象的时候,对话框类中CView*指针数据成员可以在带参数为CView*指针重载构造函数里方便获取构造它的View类指针。

6,ClassWizard并不支持用户自定义消息的响应,所以当使用用户自定义消息编程的时候,必须自己编写自定义消息的处理代码。(三步,首先是消息响应函数原型声明,其次消息映射,最后是编写消息响应函数代码。这里要注意:用户自定义消息的消息映射一定要加在BEGIN_MESSAGE_MAP(..)~~END_MESSAGE_MAP()之间,//{{AFX_MSG_MAP(CEx07aView)~~ //}}AFX_MSG_MAP注释宏对之外)

7,对于无模式对话框一定要注意不要调用CDialog::OnOk或者CDialog::OnCancel函数,既在无模式对话框类中必须重载这些虚函数;否则当使用ESC键,回车键或者用鼠标单击OK|CANCEL按钮的时候,会激发对应基类函数的调用,进而导致调用Windows 的EndDialog函数,EndDialog函数只适合于模式对话框。对于无模式对话框,必须调用DestroyWindow函数。
如果需要的话,还可调用Updatedata函数来将数据从对话框控件中传到类数据成员中。

8,Windows通用对话框:
共同特点:都从用户处获得消息,但并不对信息做处理。如:文件对话框只为程序提供路径名,字体对话框只是填充一个描叙字体的结构,并不创建字体。
所有的通用对话框类都从公有基类CCommonDialog派生而来。
COMDLG32中类列表如下:
CColorDialog  允许用户选择或创建颜色
CFileDialog  允许用户打开或者保存一个文件
CFindReplaceDialog 允许用户将一个字符串换成另一个字符串
CPageSetupDialog 允许用户输入页面参数
CFontDialog  允许用户从列出的可用字体中选择一种字体
CPrintDialog  允许用户设置打印机并打印文档

9,注意:在Win32中,不能在标准文件对话框内部动态创建控件。(其它标准对话框中也应该如此吧)

10,嵌套对话框(这些内容熔入EX07B事例中讲解了,不打算重复,强烈建议看看和跟着做做,页码:P135-141。下面只对其中重要的函数做些说明笔记。)
利用MFC,从通用
1)CFileDialog::m_ofn
//m_ofn is a structure of type OPENFILENAME. Use this structure to initialize the appearance of a File Open or File Save As dialog box after it is constructed but before it is displayed with the DoModal member function.
2)CFileDialog::CFileDialog
CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL );
//bOpenFileDialog
Set to TRUE to construct a File Open dialog box or FALSE to construct a File Save As dialog box.
3)CFileDialog::DoModal
//Call this function to display the Windows common file dialog box and allow the user to browse files and directories and enter a filename.
//If you want to initialize the various file dialog-box options by setting members of the m_ofn structure, you should do this before calling DoModal, but after the dialog object is constructed.
//When the user clicks the dialog box’s OK or Cancel buttons, or selects the Close option from the dialog box’s control menu, control is returned to your application. You can then call other member functions to retrieve the settings or information the user inputs into the dialog box.
4)CFileDialog::GetPathName
//Call this function to retrieve the full path of the file entered in the dialog box. The path of the filename includes the file’s title plus the entire directory path.
5)事例中注意设置自己创建的子对话框上的组筐控件的ID为stc32。这样才保证文件通用对话框嵌入的位置在组筐所在的位置上,否则默认为自己创建的子对话框的同宽度。(stc32应该是与文件通用对话框相关联的,具体是如何关联的哦?)
6)事例中可见到这样的代码(GetParent()->GetDlgItem(IDOK)->SetWindowText("Delete");)来获取文件通用对话框上的控件指针,这里要理解为什么要用GetParent()函数来获得父窗口指针(因为事例中自己所创建的对话框被设置成Child Style。)(Child style,None border,Group box ID=stc32这些设置都是必不可少的,自己可以试着改变这些设置,看看效果印象也就深了)
7)事例中CSpecialFileDialog::OnDelete() 函数中代码(GetParent()->GetDlgItem(0x480)->GetWindowText(m_strFileName);)通过获取文件通用对话框上文件名对应的编辑框的指针调用CWnd::GetWindowText函数来获取编辑框中的文本保存在m_strFileName数据成员中。其中0x480应该是文件通用对话框上文件名对应的编辑框的ID。
8)事例中CSpecialFileDialog::OnDelete() 函数中代码(GetParent()->SendMessage(WM_COMMAND,IDCANCEL);)向文件通用对话框发送IDCANCEL消息,该操作引起OnCancel函数的调用终止当前模式对话框同时使得CFileDialog::DoModal函数返回IDCANCEL值。
MSDN:
CDialog::OnCancel (The default simply terminates a modal dialog box by calling EndDialog and causing DoModal to return IDCANCEL.)
9)SDK函数:FindFirstFile,DeleteFile
//FindFirstFile Searches a directory for a file whose name matches the specified file name on the destination site identified by this object. It examines subdirectory names as well as file names.
//DeleteFile Deletes the given file from the destination site.
10)CFile::Remove
A static function ,deletes the file specified by the path. It will not remove a directory. (注意:用这函数删除的文件是不经过回收站的哦。)

11,在对话框标题栏添加图标:在对话框类OnInitDialog函数中添加如下代码。
 HICON hIcon =AfxGetApp()->LoadIcon(ID_MYICON);//ID_MYICON是用资源编辑器创建的图标ID。
 this->SetIcon(hIcon,TRUE);
 this->SetIcon(hIcon,FALSE);注:这里带上this指针目的是为了强调必须使用目的对话框类对象指针调用SetIcon设置图标。
比如在书EX07B事例中,由于CSpecialFileDialog类设置为子窗口类,而且所关联的资源窗口没有Tittle Bar,要在父窗口文件通用对话框Tittle Bar上添加图标,必须获取父窗口文件通用对话框对象指针来调用SetIcon设置图标。
如在书EX07B事例中:在CSpecialFileDialog::OnInitDialog函数中添加如下代码,可设置文件通用对话框标题图标: 
 HICON hIcon =AfxGetApp()->LoadIcon(ID_MYICON);
 GetParent()->SetIcon(hIcon,TRUE);
 GetParent()->SetIcon(hIcon,FALSE);

第六章:模式对话框和Windows通用控件

1,对话框也是窗口,它不当可以接受消息,而且还可以被移动和关闭,甚至可以在它的客户区中进行绘图操作。

2,模式对话框在被关闭之前,用户无法在同一应用程序的其它地方进行工作。模式对话框更易于编程。
无模式对话框在它仍保留在屏幕的同时,用户还可以在应用程序的其它窗口进行工作。

3,对话框控件既可以通过CWnd指针来引用,也可以通过资源文件定义的索引值(和#define常量相关联)来引用。对话框控件本身就是一个窗口。控件通过向上级对话框发送消息来响应用户的动作。
利用ClassWizard可以帮助产生CDialog派生类,还可以使对话框类数据成员和对话框控件相联系。

4,在现存在项目中添加模式对话框步骤:
1)用对话框编辑器创建包含各种控件的对话框资源。对话框编辑器会对项目的资源文件更新,使之包含新的对话框资源,并且该项目的resource.h文件也会被更新,以便能够包含新的#define常量。
2)利用ClassWizard创建CDialog派生类,并将它和第一步所创建的资源相连接。
3)利用ClassWizard添加控件消息响应函数,并进行编辑。
4)在其它类中需要使用地方先构造该对话框类对象,再调用DoModal显示模式对话框。
说明:
1)在产生的对话框头文件中包含一个枚举类型常量IDD,用于设置该对话框资源ID。枚举常量IDD的使用减弱了CPP文件对资源ID的依赖。
2)《在其它类中显示模式对话框后,只有当模式对话框退出后,才继续执行该类显示模式对话框代码后的代码。》

5,在组合筐中Data属性页下,添加一条后按CTRL+RETURN来结束(或添加下条item)。(VC6中按?键可以获取相关帮助提示的)。组合框有Simple,Dropdown,Drop List三中风格,可以是Styles中选择。
列表筐中,用户只能用鼠标选择选择一个条目,而且在对话框编辑器中不能输入列表框的初始选择条目。
在静态文本控件中可以内置'&'符号。运行时候,&符号后面的字符下将有一个下划线。用户在按下ALT键后同时按下相应带下划线的字母,则就可以跳转到相应的控件上去。注意同一对话框中跳转字符不能重复。

6,当DoModal被调用后,实际在幕后引起一系列如下的动作:
CDialog::DoModal->CEx06Dialog::OnInitDialog->其它的初始化->CDialog::OnInitDialog->CWnd::UpdateData(FALSE)->CEx06Dialog::DoDataExchange
用户输入数据...
用户单击OK按钮
CEx06Dialog::OnOk->...其它的确认处理...->CDialog::OnOk->CWnd::UpDateData(TURE)->CEx06Dialog::DoDataExchange->CDialog::EndDialog(IDOK)
说明:
1)virtual BOOL OnInitDialog( );
//CDialog::OnInitDialog This member function is called in response to the WM_INITDIALOG message. This message is sent to the dialog box during the Create, CreateIndirect, or DoModal calls, which occur immediately before the dialog box is displayed.
//Override this member function if you need to perform special processing when the dialog box is initialized.

2)BOOL UpdateData( BOOL bSaveAndValidate = TRUE );
//CWnd::UpdateData :Call this member function to initialize data in a dialog box, or to retrieve and validate dialog data.
//bSaveAndValidate:Flag that indicates whether dialog box is being initialized (FALSE) or data is being retrieved (TRUE).
//By default UpdateData(TRUE) is called in the default CDialog::OnOK handler and UpdateData(FALSE) is called in the default CDialog::OnInitDialog.

3)virtual void DoDataExchange( CDataExchange* pDX );
//CWnd::DoDataExchange  Called by the framework to exchange and validate dialog data.
//Never call this function (DoDataExchange) directly. It is called by the UpdateData member function.
//Call UpdateData to initialize a dialog box’s controls or retrieve data from a dialog box.

4)void EndDialog( int nResult );
//CDialog::EndDialog  makes the dialog box invisible but does not destroy it.
//Call this member function to terminate a modal dialog box. This member function returns nResult as the return value of DoModal(IDOK表示接受对话框数据,IDCANCEL表示取消对话框数据). You must use the EndDialog function to complete processing whenever a modal dialog box is created.
//注意:If you implement the OK button in a modeless dialog box, you must override the OnOK member function and call DestroyWindow from within it.

5)当DoModal函数返回的时候,对话框窗口不再存在。我们可以在堆栈中创建模式对话框对象,这样就可以保证当程序控制转向到C++对话框对象所在的范围之外时,它及时的删除掉。


7,代码解释:
void CEx06aDialog::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CEx06aDialog)
 DDX_Text(pDX, IDC_BIO, m_strBio);//
 DDX_Radio(pDX, IDC_CAT, m_nCat);
 ...
 DDV_MinMaxInt(pDX, m_nSsn, 0, 999999999);
 //}}AFX_DATA_MAP
}
说明:
1)DoDataExchange、DDX_(交换)、DDV_(确认)函数都具有双向性。如果调用UpdateData(FALSE)(参数为FALSE),则这些数据就会将与控件相关联(值关联)的数据成员的值传递给对话框中的控件;相反,如果UpDateData(TURE)(参数是TURE),则这些函数会将数据从对话框控件中传递给与之相关联(值关联)的数据成员。
2)这里DDX_Text函数被重载,具体参阅MSDN。The DDX_Text function manages the transfer of int, UINT, long, DWORD, CString, float, or double data between an edit control in a dialog box, form view, or control view and a CString data member of the dialog box, form view, or control view object.
其它DDX_函数参阅MSDN。

8,Enter键触发OnOk函数调用:
当用户按下ENTER键后,OS会自动去查找输入焦点落在哪个按钮上,获得焦点的按钮四周将被点线矩形框包围。如果所有的按钮都没获得输入焦点,则OS会自动去寻找程序或资源所指定的默认按钮(默认按钮边框较粗)。如果对话框没有默认按钮,那么即使对话框中没有OK按钮,OnOk函数也会自动被调用。
由于OnOk函数是虚函数,可以重写OnOk函数,将其函数体置空,变可以使使ENTER键无效。
分离OK按钮:改写OK按钮ID,并除掉其默认按钮(Default Button)的设置。

9,p107至WIN32程序员:强烈建议看看,下为简要笔记。
对话框控件会向他们父对话框发送WM_COMMAND通告消息。大多数窗口程序处理函数都是通过一个嵌套的switch结构了处理这些通告消息的,而MFC则更直接了当地把这些控件通知消息和其它的Windows消息放在同一个层次上处理。

10,Esc键触发OnCancel函数的调用,导致控制从对话框中退出,如果是模式对话框则DoModal的还返回IDCANCEL值。其消除方法同ENTER键。

11,事例代码涉及的一些主要函数及补充说明:
1)CWnd* GetDlgItem( int nID ) const;//可用它来获取对话框上控件指针(返回的时候,强制转换成所需要的控件指针),注意临时性。
   void CWnd::GetDlgItem( int nID, HWND* phWnd ) const;
//Retrieves a pointer to the specified control or child window in a dialog box or other window. The pointer returned is usually cast to the type of control identified by nID.
说明:如果需要包CWnd指针转化成一个控件ID,则可以使用MFC中CWnd类GetDlgCtrlID成员函数。
2)GetScrollPos  Retrieves the current position of a scroll box.
   SetScrollPos  Sets the current position of a scroll box.
   GetScrollRange  Retrieves the current minimum and maximum scroll-bar positions for the given scroll bar.
   SetScrollRange  Sets minimum and maximum position values for the given scroll bar.
3)afx_msg void OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );//CWnd::OnHScroll 
afx_msg void OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );//CWnd::OnVScroll 
3)所有的水平滚动条都绑在WM_HSCROLL消息控制函数,所有的竖直滚动条则都绑在一个WM_VSCROLL消息控制函数上。(一般控件都有自己的独立的消息控制函数,但[滚动条控件]有点不同,所以对同一个对话框多个滚动条消息处理的时候,一般都将它们的滚动范围设置一致,方便编程)


/////////////////////////
/////////////////////////
///P109-125页内容笔记待续
12,每个控件在显示之前会向其父对话框发送WM_CTLCOLOR消息,对话框本身也会发送该消息。
《对话框和对话框控件都是窗口,也可以在这些窗口中进行绘图操作。(添加OnPain函数,调用Invalidate/UpdateWindow让窗口重绘)》

13,在运行时加入对话框控件:
一般步骤:
1)在对话框类中添加一个内嵌的控件窗口数据成员。一个内嵌控件C++对象将与相应的对话框对象一起被构造和删除。
2)从View菜单中选择Resource Symbols,为新的控件添加一个ID常量。(也可以在Resource.h中用定义)
3)用ClassWizard映射WM_INITDIALOG消息覆盖(Override)基类 CDialog::OnInitDialog函数。在该函数里调用控件窗口的Create成员函数,并显示新的控件(可以用ShowWindow函数)。Windows回在删除对话框窗口的同时也删除该控件窗口。
4)在派生对话框类里,为新控件手工加入必要的通知消息控制函数。(三步:消息控制函数原型说明,消息映射,消息处理函数)

14,Win32编程经验:父窗口和控件之间是通过Windows消息进行通信的(如MFC中象CListBox::InserString函数),但适用于所有窗口类型的控件类成员函数并不发送消息,而是调用Win32函数。

15,Windows通用控件:Win95引进的象[进度指示器],[滑杆条],[微调按钮控件],[列表控件]和[树状控件]。这些控件的代码在Windows的COMCTL32.DLL文件中,其中包括了每个控件的窗口过程函数,及每个控件的注册窗口类的代码,这些注册代码在DLL加载时候被调用。当应用程序初始化对话框时,将使用对话框资源中符号化的类名,来连接到DLL里的窗口过程函数上。这样应用程序就有了控件的窗口,但代码实际上在DLL里。
除了ActiveX控件,大多数控件都是用这种方法实现的。

16,WM_NOTIFY
    idCtrl = (int) wParam; //控件ID
    pnmh = (LPNMHDR) lParam; //指向NMHDR结构指针,该结构由控件管理。
说明:
1)Sent by a common control to its parent window when an event has occurred in the control or the control requires some kind of information.
2)Not all controls will send WM_NOTIFY messages. In particular, the standard Windows controls (edit controls, combo boxes, list boxes, buttons, scroll bars, and static controls) do not send WM_NOTIFY messages

第五章:图形设备接口(GDI)、颜色及字体

1,任何时候当程序需要直接在屏幕或打印机上绘图的时候,都需要调用GDI函数,GDI函数包含了一些用于绘制图形、位图以及文本的函数。

2,Windows的设备环境是GDI的关键元素,它代表了物理设备。每一个C++设备环境对象都有与之对应的Windows设备环境,并且通过一个32位类型的HDC句柄来标识。

3,MFC库设备环境类基类CDC包含了绘图所需要的所有成员函数,并且几乎所有派生类只有构造函数和析构函数不同(CMetaFileDC类除外)。
对于显示器来说,常用的派生类有CClientDC 和 CWindowDC,而对其它设备(如打印机或内存缓冲区),则可以构造一个基类CDC的对象。
对于显示器和打印机设备环境对象来说,应用程序框架会直接将句柄附在对象上;而对其它设备环境(如内存设备环境),为了将对象与句柄相联系,在构造完对象之后,还必须调用一个成员函数(进行初试化)。

4,CClientDC类 和 CWindowDC类
CClientDC( CWnd* pWnd );
//Constructs a CClientDC object that accesses the client area of the CWnd pointed to by pWnd. The constructor calls the Windows function GetDC.

CWindowDC( CWnd* pWnd );
//Constructs a CWindowDC object that accesses the entire screen area (both client and nonclient) of the CWnd object pointed to by pWnd. The constructor calls the Windows function GetWindowDC.

如果构造CClientDC对象,则设备环境的映射区域限于客户区域,不能在客户区域外绘图。原点(0,0)在客户区左上角。
《 如果创建CWindowDC对象,则设备环境的映射区域为整个窗口(包括标题栏、状态栏、窗口边框等)。原点(0,0)在整个窗口的左上角。》
注意:
1)视图窗口没有非客户区域.
2)视图窗口覆盖在框架窗口之上。
3)在《》中的内容,是我根据测试所理解的。翻译原文中映射区域是整个显示屏幕,原点(0,0)在整个屏幕的左上角。这显然是不对的。

5,在创建了一个CDC对象后,一定要注意在完成任务后将其删除。(如果用CClientDC 或 CWindowDC来在堆栈中构造一个DC对象,则不需要我们显式的删除它,CClientDC或CWindowDC对象会在它的生命周期结束的时候自动调用析构函数来完成删除工作)
例如:
CDC *pDC=GetDC();
...
RealeaseDC(pDC);
说明:
CDC* GetDC( );//CWnd::GetDC 获得与当前窗口相关联的CDC对象指针(映射窗口客户区域)
int ReleaseDC( CDC* pDC );//CWnd::ReleaseDC 释放与当前窗口相关联的设备环境

注意:
在MFC程序中,千万不能自己添加代码删除作为参数以指针形式传递给OnDraw(CDC* pDC)函数的CDC对象,应用程序会自动控制它的删除。

6,当利用CDC对象绘图的时候,所绘制的图形都要依赖于设备环境的状态:如画笔、画刷、字体等GDI绘图对象 和 当前映射模式的选择等。
可以使用CDC成员函数了设置所需要的饿设备环境状态。如:SelectObject()函数可将GDI对象随时选入设备环境中。

7,CPaintDC类:当需要重写OnPaint函数的时候,就需要使用CPaintDC类。默认的OnPaint函数会使用已经设置好的设备环境来调用OnDraw函数
注意:CPaintDC类的构造函数和析构函数所完成的工作都是针对显示用的。
例:
void CMyView::OnPaint()
{
CPaintDC dc(this);
OnPrepareDC(&dc);
dc.TextOut(0,0,"for the display,not the printer");
OnDraw(&dc);
}
说明:
1)CPaintDC( CWnd* pWnd );
//CPaintDC::CPaintDC Constructs a CPaintDC object, prepares the application window for painting, and stores the PAINTSTRUCT structure in the m_ps member variable.
2)CPaintDC类的构造函数自动调用BeginPaint,而它的析构函数会自动调用EndPaint.
3)CDC* BeginPaint( LPPAINTSTRUCT lpPaint );
//CWnd::BeginPaint Prepares CWnd for painting and fills a PAINTSTRUCT data structure with information about the painting.
void EndPaint( LPPAINTSTRUCT lpPaint );
//CWnd::EndPaint Marks the end of painting in the given window. The EndPaint member function is required for each call to the BeginPaint member function, but only after painting is complete.
问题:
1)在View类中一旦定义了OnPaint()函数,则WM_PAINT消息由OnPaint函数来响应。OnDraw函数不再被调用。原因?


8,GDI对象:
Class   Windows handle type

CPen   HPEN
CBrush   HBRUSH
CFont   HFONT
CBitmap  HBITMAP
CPalette  HPALETTE
CRgn   HRGN
说明:
Each graphic-object class in the class library has a constructor that allows you to create graphic objects of that class, which you must then initialize with the appropriate create function, such as CreatePen.

Each graphic-object class in the class library has a cast operator that will cast an MFC object to the associated Windows handle. The resulting handle is valid until the associated object detaches it. Use the object’s Detach member function to detach the handle.

9,CGdiObject类有一个虚析构函数,在其派生类的析构函数将与C++对象相关联的WINDOWS GDI对象删除掉。如果构造了一个CGdiObject派生类对象,则在退出程序之前,必须将其删除掉。
利用CDC类的SelectObject成员函数把自己的GDI对象选进DC的同时,保存原来的GDI对象,当任务完成后,恢复原来的GDI对象,这样就可以将自己的GDI对象的删除掉。
如:
GDIStyle *poldGdiObject=pDC->SelectObject(&newGdiObject);
...//完成任务
pDC->SelectObject(poldGdiObject);

10,Windows对任何企图删除库存GDI对象的行为都不予理会。可以利用SelectObject函数把库存GDI对象选入,从而删除当前GDI对象。
原因:
This function SelectObject may return a pointer to a temporary object. This temporary object is only valid during the processing of one Windows message.
如:
pDC->SelectObject(&newGdiObject);
...
pDC->SelectStockObject(StockCGdiObject);//如:BLACK_BRUSH

11,对于显示设备环境,在消息处理函数内部所进行GDI选择在函数退出后不再有效,因此在进入其他处理函数的时候,每次都必须重新设置设备环境。
Windows句柄是唯一能够持久存在的GDI标识。可以使用GDI对象指针调用GetSafeHandle函数可以获得它Windows句柄,再利用GDI对象类的FromHandle函数将句柄转化为对应的GDI对象。
如:
CFont *pOldFont=pDC->SelectObject(&newFont);
m_hOldFont=(HFONT)pOldFont->GetSafeHandle();//m_hOldFont为数据成员,保存先前字体对象句柄
...
pDC->SelectObject(CFont::FromHandle(m_hOldFont));//可在其他函数中,恢复m_hOldFont句柄对应的字体对象。
说明:
1)static CFont* PASCAL FromHandle( HFONT hFont );
//CFont::FromHandle Returns a pointer to a CFont object when given an HFONT handle to a Windows GDI font object. If a CFont object is not already attached to the handle, a temporary CFont object is created and attached.
2)CGdiObject::GetSafeHandle();
//Return A HANDLE to the attached Windows GDI object; otherwise NULL if no object is attached.

12,每一种Windows颜色都是 通过8位的红(R)、绿(G)、蓝(B)的值祝贺来表示的。
面向颜色的GDI函数可以接收32位的COLORREF参数。Windows的RGB宏可以将8位的红绿蓝值转化成COLORREF参数。
说明:
1)The COLORREF value is a 32-bit value used to specify an RGB color.
2)16种标准VGA纯色参见 P70页;256显示卡 多增加4种标准色参见 P71页。

13,字体是GDI对象,在使用上和其它的GDI对象完全一样。
CDC::GetTextMetrics 
BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics ) const;//测量字体高度等参数

14,GetDeviceCaps();
//Retrieves a wide range of device-specific information about the display device.

 

第四章:基本事件处理、映射模式和滚动视图


1,消息映射:如在视窗中按下鼠标做键,会自动发送WM_LBUTTONDOWN消息,如果要对这消息有所反应的话,需

//{{AFX_MSG(CEx04aView)
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);//头文件声明消息响应函数原型。
//}}AFX_MSG
DECLARE_MESSAGE_MAP()//头文件

BEGIN_MESSAGE_MAP(CDrawView, CView)//代码文件
 //{{AFX_MSG_MAP(CEx04aView)
 ON_WM_LBUTTONDOWN()//该消息映射宏将OnLButtonDown函数和应用程序框架联系在一起
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) //代码文件
{
 //event processing code here
}
说明:
为了方便ClassWizard,AppWizard生成了一些注释行。它把消息映射函数原型放在两个AFX_MSG“刮弧对”之间,在AFX_MSG_MAP“刮弧对”之间添加消息映射入口,并在代码文件中给出完整的OnLButtonDown成员函数框架。

2,视图中的OnDraw()是根据视图当前状态来绘制图象的,用户的操作可以改变这中状态。在完整的MFC库应用程序中,文档的对象掌握在应用程序(视图)的状态。

3,如果用全程变量来保存视图状态,这将在多视图情况下会遇到麻烦;(待体会)

4,CWnd::InvalidateRect函数能够触发WM_PAINT消息,该消息被窗口类如CView映射后,引起对OnDraw函数调用,从而重绘无效矩形区域。
优化窗口的绘制过程:
1)设置的无效区域越小,重画的速度就越快;
2)执行无效区域外的绘制纯属于浪费时间,OnDraw函数可以调用CDC的成员函数GetClipBox得到无效区域大小。
注意:
OnDraw函数不仅仅响应InValidate*之类的调用,它也会在窗口改变大小和窗口显露时被调用。

5,本章重要介绍函数
PtInRect(..);//测试一个点是否落在某个矩形内。
PtInRegion(..);//判断一个点是否落在椭圆(CRgn对象)内//A region is an elliptical or polygonal area within a window.
GetClientRect(..);//获得客户矩形坐标并保持在CRect对象中
SelectStockObject(..);//选择the predefined stock pens, brushes, or fonts到DC中,函数返回先前的CGdiObject 对象指针。

6,在构造函数中对类数据成员初始化。
CEx04aView::CEx04aView() : m_rectEllipse(0, 0, 200, 200)//注意这种初试化方式,m_rectEllipse是CEx04aView类数据成员CRect类对象
{
 m_nColor = GRAY_BRUSH;
}

7,[致WIN32程序员]:
 标准的基于WINDOWS应用程序会首先登记一个窗口类(不同于C++类[补:实际是个_WNDCLASS结构体]),同时在处理过程中,还需要对每个类指定窗口过程(WINDOWS PROCEDURE)。每次应用程序调用CreateWindow建立一个窗口时候,都要指定一个窗口类做为参数,这样就把新建立的窗口和窗口过程函数连接起来了。每次Windows给窗口发送消息时候,这个函数就会被调用(补:消息循环中DispatchMessage(&msg)分派消息到窗口的回调函数处理,OS调用窗口回调函数进行处理),以检查用参数传送进来的消息码,并执行适当的代码来处理该消息。
 MFC库应用程序框架有一个适用于大多数窗口类型的简单窗口类和窗口过程函数。该窗口过程函数会根据参数传进来的窗口句柄,在MFC的句柄映射表(handle map)中查找,从而得到对应的C++窗口对象指针。然后,该窗口过程函数用MFC运行时类(runtime class)系统来决定窗口对象的C++类。下一步,它从由消息分发映射函数生成的静态表中找到消息处理函数,最后用正确的窗口对象调用消息处理函数。

8,映射模式:
1)MM_TEXT映射模式:坐标被映射到象素,X值向右递增,Y值向下递增。可用它来表示[设备坐标]。
CDC::SetMapMode(..)//设置映射模式
CDC::GetMapMode(..)
CDC::SetViewportOrg(..)//设置视口原点
CDC::GetViewportOrg(..)
CDC::SetWindowOrg (..)//设置屏幕原点
CDC::GetWindowOrg(..)
2)固定比例映射模式(MM_HIENGLISH,MM_HIMETRIC ,MM_LOMETRIC ,MM_LOENGLISH,MM_TWIPS )
固定比例映射模式均X值向右递增,Y值向下递减,它们之间唯一差别是 实际的比例因子。如下:
MM_HIENGLISH   Each logical unit is converted to 0.001 inch.
MM_HIMETRIC   Each logical unit is converted to 0.01 millimeter.
MM_LOENGLISH   Each logical unit is converted to 0.01 inch.
MM_LOMETRIC   Each logical unit is converted to 0.1 millimeter.
MM_TWIPS   Each logical unit is converted to 1/20 of a point(磅). (Because a point is 1/72 inch, a twip is 1/1440 inch.)
//MM_TWIPS常常用于打印机。        
3)可变比例映射模式:(MM_ISOTROPIC ,MM_ANISOTROPIC )
这两种模式用许我们改变它们的比例因子和坐标原点。
应用这两中模式,如用户改变窗口的尺寸,绘制的图形大小也会发生响应的变化
具体如下:
The MM_HIENGLISH, MM_HIMETRIC, MM_LOENGLISH, MM_LOMETRIC, and MM_TWIPS modes are useful for applications that must draw in physically meaningful units (such as inches or millimeters). The MM_ISOTROPIC mode ensures a 1:1 aspect ratio, which is useful when it is important to preserve the exact shape of an image. The MM_ANISOTROPIC mode allows the x- and y-coordinates to be adjusted independently
常一起使用的函数:
SetWindowExt(..)//Sets the x- and y-extents of the window associated with the device context.
SetViewportExt(..)//Sets the x- and y-extents of the viewport of the device context. 

注意:
When the following mapping modes are set, calls to SetWindowExt and SetViewportExt functions are ignored:
 MM_HIENGLISH,MM_HIMETRIC,MM_LOENGLISH,MM_LOMETRIC,MM_TEXT,MM_TWIPS
When MM_ISOTROPIC mode is set, an application must call the SetWindowExt member function before calling SetViewportExt.

9,坐标变换:(具体参见P54)
许多MFC库函数只能在设备坐标下工作(尤其CRect类成员函数)。可以认为CDC的所有成员函数都一逻辑坐标作参数。可以认为CWnd的成员函数都以设备坐标做参数。(所有在实际窗口上点击获得的坐标都是逻辑坐标)。在设置了设备环境的映射模式及相应的参数以后,CDC的LPtoDP和DPtoLP函数可以用来在逻辑坐标系和设备做表系之间进行转换。
在CView的虚函数OnPrepareDC中设置映射模式要比在OnDraw函数中要好。
//*注意:
CView::OnPrepareDC
virtual void OnPrepareDC( CDC* pDC, CPrintInfo* pInfo = NULL );
应用程序将在调用OnDraw之前调用OnPrepareDC函数。
(OnPrepareDC在为屏幕显示而调用OnDraw函数之前,或在为打印或打印预览每一页而调用OnPrint成员函数之前。)

10,CScrollView支持滚动条的滚动,但不支持键盘的滚动。通过使用CWnd的ScrollWindow和SetViewportOrg函数,CScrollView类允许将视口原点移到窗口中的任何一个位置,甚至包括窗口区域的上部或窗口的原点的左边。

键盘输入是分两步处理的。OS向窗口发送类如WM_KEYDOWN和WM_KEYUP消息时用的是虚拟键盘码,在消息到达窗口之前,被翻译成WM_CHAR消息,该消息带着正常的键码。

利用对WM_KEYDOWN消息进行响应,对按键分别调用OnVScroll就可以使应用程序支持键盘的滚动。
CWnd::OnVScroll 
afx_msg void OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar );
////
nSBCode:
SB_BOTTOM   Scroll to bottom.
SB_ENDSCROLL   End scroll.
SB_LINEDOWN   Scroll one line down.
SB_LINEUP   Scroll one line up.
SB_PAGEDOWN   Scroll one page down.
SB_PAGEUP   Scroll one page up.
SB_THUMBPOSITION   Scroll to the absolute position. The current position is provided in nPos.
SB_THUMBTRACK   Drag scroll box to specified position. The current position is provided in nPos.
SB_TOP   Scroll to top.
////
The framework calls this member function(OnVScroll) when the user clicks the window’s vertical scroll bar.


11,CView::OnInitialUpdate
virtual void OnInitialUpdate( );
说明:
OnInitialUpdate是视图窗口完全建立后框架调用的第一个函数。框架在第一次调用OnDraw前会调用OnInitialUpdate。
具体参见下:
Called by the framework after the view is first attached to the document, but before the view is initially displayed. The default implementation of this function calls the OnUpdate member function with no hint information .

12,MFC对140种Windows消息直接直接提供了相应的消息控制函数,当然,我们还可以定义自己的消息和相应的消息控制函数。
五种特殊Windows消息:WM_CREATE,WM_CLOSE,WM_QUERYENDSESSION,WM_DESTROY,WM_NCDESTROY.(具体参见 p62-63页。这两页强烈建议看看,这里简要笔记三个最常用最重要的)
1)WM_CREATE消息:
The WM_CREATE message is sent when an application requests that a window be created by calling the CreateWindowEx or CreateWindow function. The window procedure of the new window receives this message after the window is created, but before the window becomes visible. The message is sent before the CreateWindowEx or CreateWindow function returns.
2)WM_CLOSE消息:
当关闭窗口或父窗口被关闭时,Windows都会发送WM_CLOSE消息。可以重新定义该消息响应函数OnClose来完全控制关闭过程。
3)WM_DESTROY消息:
Windows在发送WM_CLOSE消息之后,紧接着就会发送WM_DESTROY消息(响应这个消息的时候,窗口已经消失但还没有销毁)。
(可以响应这个消息来做一些销毁当前窗口后的一些事情,例如再弹出其它对话框发送其他的消息)


 
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:57086次
    • 积分:1065
    • 等级:
    • 排名:千里之外
    • 原创:50篇
    • 转载:3篇
    • 译文:0篇
    • 评论:8条
    文章分类
    最新评论