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

📄 ch03.htm

📁 Using Visual C++ 6.0 一本关于Visual C++ 6.0基本编程应用的书籍。
💻 HTM
📖 第 1 页 / 共 3 页
字号:
	<LI>ON_COMMAND--Used to delegate the handling of a specific command to a member function
	of the class.
	<P>
	<LI>ON_COMMAND_RANGE--Used to delegate the handling of a group of commands, expressed
	as a range of command IDs, to a single member function of the class.
	<P>
	<LI>ON_CONTROL--Used to delegate the handling of a specific custom control-notification
	message to a member function of the class.
	<P>
	<LI>ON_CONTROL_RANGE--Used to delegate the handling of a group of custom control-notification
	messages, expressed as a range of control IDs, to a single member function of the
	class.
	<P>
	<LI>ON_MESSAGE--Used to delegate the handling of a user-defined message to a member
	function of the class.
	<P>
	<LI>ON_REGISTERED_MESSAGE--Used to delegate the handling of a registered user-defined
	message to a member function of the class.
	<P>
	<LI>ON_UPDATE_COMMAND_UI--Used to delegate the updating for a specific command to
	a member function of the class.
	<P>
	<LI>ON_COMMAND_UPDATE_UI_RANGE--Used to delegate the updating for a group of commands,
	expressed as a range of command IDs, to a single member function of the class.
	<P>
	<LI>ON_NOTIFY--Used to delegate the handling of a specific control-notification message
	with extra data to a member function of the class.
	<P>
	<LI>ON_NOTIFY_RANGE--Used to delegate the handling of a group of control-notification
	messages with extra data, expressed as a range of child identifiers, to a single
	member function of the class. The controls that send these notifications are child
	windows of the window that catches them.
	<P>
	<LI>ON_NOTIFY_EX--Used to delegate the handling of a specific control-notification
	message with extra data to a member function of the class that returns TRUE or FALSE
	to indicate whether the notification should be passed on to another object for further
	reaction.
	<P>
	<LI>ON_NOTIFY_EX_RANGE--Used to delegate the handling of a group of control-notification
	messages with extra data, expressed as a range of child identifiers, to a single
	member function of the class that returns TRUE or FALSE to indicate whether the notification
	should be passed on to another object for further reaction. The controls that send
	these notifications are child windows of the window that catches them.
</UL>

<P>In addition to these, there are about 100 macros, one for each of the more common
messages, that direct a single specific message to a member function. For example,
ON_CREATE delegates the WM_CREATE message to a function called OnCreate(). You cannot
change the function names in these macros. Typically, these macros are added to your
message map by ClassWizard, as demonstrated in Chapter 8.</P>
<P>
<H3><A NAME="Heading5"></A>How Message Maps Work</H3>
<P>The message maps presented in Listings 3.3 and 3.4 are for the CShowStringApp
class of the ShowString application. This class handles application-level tasks such
as opening a new file or displaying the About box. The entry added to the header
file's message map can be read as &quot;there is a function called OnAppAbout() that
takes no parameters.&quot; The entry in the source file's map means &quot;when an
ID_APP_ABOUT command message arrives, call OnAppAbout().&quot; It shouldn't be a
big surprise that the OnAppAbout() member function displays the About box for the
application.</P>
<P>If you don't mind thinking of all this as magic, it might be enough to know that
adding the message map entry causes your code to run when the message is sent. Perhaps
you're wondering just how message maps really work. Here's how. Every application
has an object that inherits from CWinApp, and a member function called Run(). That
function calls CWinThread::Run(), which is far longer than the simple WinMain() presented
earlier but has the same message loop at its heart: call GetMessage(), call TranslateMessage(),
call DispatchMessage(). Almost every window object uses the same old-style Windows
class and the same WindProc, called AfxWndProc(). The WindProc, as you've already
seen, knows the handle, hWnd, of the window the message is for. MFC keeps something
called a <I>handle map</I>, a table of window handles and pointers to objects, and
the framework uses this to send a pointer to the C++ object, a CWnd*. Next, it calls
WindowProc(), a virtual function of that object. Buttons or views might have different
WindowProc() implementations, but through the magic of polymorphism, the right function
is called.</P>


<BLOCKQUOTE>
	<P>
<HR>
<B>Polymorphism</B><BR>
	</P>

	<P>Virtual functions and polymorphism are important C++ concepts for anyone working
	with MFC. They arise only when you are using pointers to objects and when the class
	of objects to which the pointers are pointing is derived from another class. Consider
	as an example a class called CDerived that is derived from a base class called CBase,
	with a member function called Function() that is declared in the base class and overridden
	in the derived class. There are now two functions: One has the full name CBase::Function(),
	and the other is CDerived::Function().<BR>
	</P>

	<P>If your code has a pointer to a base object and sets that pointer equal to the
	address of the derived object, it can then call the function, like this:
	<PRE>    CDerived derivedobject;
    CBase* basepointer;
    basepointer = &amp;derivedobject;
    basepointer-&gt;Function();</PRE>

</BLOCKQUOTE>

<PRE></PRE>


<BLOCKQUOTE>
	<P>In this case, CBase::Function() will be called. However, there are times when
	that is not what you want--when you have to use a CBase pointer, but you really want
	CDerived::Function() to be called. To indicate this, in CBase, Function() is declared
	to be virtual. Think of it as an instruction to the compiler to override this function,
	if there is any way to do it.<BR>
	</P>

	<P>When Function() is declared to be virtual in the base class, CBase, the code fragment
	above would actually call CDerived::Function(), as desired. That's polymorphism,
	and that shows up again and again when using MFC classes. You use a pointer to a
	window, a CWnd*, that really points to a CButton or a CView or some other class derived
	from CWnd, and when a function such as WindowProc() is called, it will be the derived
	function--CButton::WindowProc() for example--that is called.
<HR>
<BR>
	
<HR>
<strong>NOTE:[</strong> You might wonder why the messages can't just be handled by virtual
	functions. This would make the virtual tables enormous, and slow the application
	too much. The message map system is a much faster approach.&#160;n
<HR>


</BLOCKQUOTE>

<P>WindowProc()calls OnWndMsg(), the C++ function that really handles messages. First,
it checks to see whether this is a message, a command, or a notification. Assuming
it's a message, it looks in the message map for the class, using the member variables
and functions set up by DECLARE_MESSAGE_MAP, BEGIN_MESSAGE_MAP, and END_MESSAGE_MAP.
Part of what those macros arrange is to enable access to the message map entries
of the base class by the functions that search the message map of the derived class.
That means that if a class inherits from CView and doesn't catch a message normally
caught by CView, that message will still be caught by the same CView function as
inherited by the derived class. This message map inheritance parallels the C++ inheritance
but is independent of it and saves a lot of trouble carrying virtual functions around.</P>
<P>The bottom line: You add a message map entry, and when a message arrives, the
functions called by the hidden message loop look in these tables to decide which
of your objects, and which member function of the object, should handle the message.
That's what's really going on behind the scenes.</P>
<P>
<H3><A NAME="Heading6"></A>Messages Caught by MFC Code</H3>
<P>The other great advantage of MFC is that the classes already catch most of the
common messages and do the right thing, without any coding on your part at all. For
example, you don't need to catch the message that tells you that the user has chosen
File, Save As--MFC classes catch it, put up the dialog box to obtain the new filename,
handle all the behind-the-scenes work, and finally call one of your functions, which
must be named Serialize(), to actually write out the document. (Chapter 7, &quot;Persistence
and File I/O,&quot; explains the Serialize() function.) You need only to add message
map entries for behavior that is not common to all applications.</P>
<P>
<H2><A NAME="Heading7"></A>Learning How ClassWizard Helps You Catch Messages</H2>
<P>Message maps may not be simple to read, but they are simple to create if you use
ClassWizard. There are two ways to add an entry to a message map in Visual C++ 6.0:
with the main ClassWizard dialog box or with one of the new dialog boxes that add
message handlers or virtual functions. This section shows you these dialog boxes
for ShowString, rather than work you through creating a sample application.</P>
<P>
<H3><A NAME="Heading8"></A>The ClassWizard Tabbed Dialog Box</H3>
<P>The main ClassWizard dialog box is displayed by choosing View, ClassWizard or
by pressing Ctrl+W. ClassWizard is a tabbed dialog box, and Figure 3.1 shows the
Message Maps tab. At the top of the dialog box are two drop-down list boxes, one
that reminds you which project you are working on (ShowString in this case) and the
other that reminds you which class owns the message map you are editing. In this
case, it is the CShowStringApp class, whose message map you have already seen.</P>
<P><A HREF="javascript:popUp('03uvc01.gif')"><B>FIG. 3.1</B></A><B> </B><I>ClassWizard
makes catching messages simple.</I></P>

<P>Below those single-line boxes is a pair of multiline boxes. The one on the left
lists the class itself and all the commands that the user interface can generate.
Commands are discussed in the &quot;Commands&quot; section later in this chapter.
With the classname highlighted, the box on the right lists all the Windows messages
this class might catch. It also lists a number of virtual functions that catch common
messages.</P>
<P>To the right of those boxes are buttons where you can add a new class to the project,
add a function to the class to catch the highlighted message, remove a function that
was catching a message, or open the source code for the function that catches the
highlighted message. Typically, you select a class, select a message, and click Add
Function to catch the message. Here's what the Add Function button sets in motion:</P>
<P>

<UL>
	<LI>Adds a skeleton function to the bottom of the source file for the application
	<P>
	<LI>Adds an entry to the message map in the source file
	<P>
	<LI>Adds an entry to the message map in the include file
	<P>
	<LI>Updates the list of messages and member functions in the dialog box
</UL>

<P>After you add a function, clicking Edit Code makes it simple to start filling
in the behavior of that function. If you prefer, double-click the function name in
the Member Functions list box.</P>
<P>Below the Object IDs and Messages boxes is a list of the member functions of this
class that are related to messages. This class has two such functions:</P>
<P>

<UL>
	<LI>InitInstance()--Overrides a virtual function in CWinApp, the base class for CShowStringApp,
	and is labeled with a V (for <I>virtual</I> function) in the list.
	<P>
	<LI>OnAppAbout()--Catches the ID_APP_ABOUT command and is labeled with a W (for Windows
	message) in the list.
</UL>

<P>The InitInstance function is called whenever an application first starts. You
don't need to understand this function to see that ClassWizard reminds you the function
has been over-ridden.</P>
<P>Finally, under the Member Functions box is a reminder of the meaning of the highlighted
message. called to implement wait cursors is a description of the DoWaitCursor virtual
function.</P>
<P>
<H3><A NAME="Heading9"></A>The Add Windows Message Handler Dialog Box</H3>
<P>In release 5.0 of Visual C++, a new way of catching messages was added. Rather
than opening ClassWizard and then remembering to set the right classname in a drop-down
list box, you right-click on the classname in ClassView and then choose Add Windows
Message Handler from the shortcut menu that appears. Figure 3.2 shows the dialog
box that appears when you make this choice.</P>
<P><A HREF="javascript:popUp('03uvc02.gif')"><B>FIG. 3.2</B></A><B> </B><I>The New
Windows Message and Event Handlers dialog box is another way to catch messages.</I></P>

<P>This dialog box doesn't show any virtual functions that were listed in the main
ClassView dialog box. It is easy to see that this class catches the command ID_APP_ABOUT
but doesn't catch the command update. (Commands and command updating are discussed
in more detail later in this chapter.) To add a new virtual function, you right-click
on the class in ClassView and choose Add New Virtual Function from the shortcut menu.
Figure 3.3 shows this dialog box.</P>
<P><A HREF="javascript:popUp('03uvc03.gif')"><B>FIG. 3.3</B></A><B> </B><I>The New
Virtual Override dialog box simplifies implementing virtual functions.</I></P>

<P>You can see in Figure 3.3 that CShowStringApp already overrides the InitInstance()
virtual function, and you can see what other functions are available to be overridden.
As in the tabbed dialog box, a message area at the bottom of the dialog box reminds
you of the purpose of each function: In fact, the text--Called to implement wait
cursors--is identical to that in Figure 3.1.</P>
<P>
<H3><A NAME="Heading10"></A>Which Class Should Catch the Message?</H3>
<P>The only tricky part of message maps and message handling is deciding which class
should catch the message. That's a decision you can't make until you understand all
the different message and command targets that make up a typical application. The
choice is usually one of the following:</P>
<P>

<UL>
	<LI>The active view
	<P>
	<LI>The document associated with the active view
	<P>
	<LI>The frame window that holds the active view
	<P>
	<LI>The application object
</UL>

<P>Views, documents, and frames are discussed in Chapter 4, &quot;Documents and Views.&quot;</P>
<P>
<H2><A NAME="Heading11"></A>Recognizing Messages</H2>
<P>There are almost 900 Windows messages, so you won't find a list of them all in
this chapter. Usually, you arrange to catch messages with ClassWizard and are presented
with a much shorter list that is appropriate for the class you are catching messages
with. Not every kind of window can receive every kind of message. For example, only
classes that inherit from CListBox receive list box messages such as LB_SETSEL, which
directs the list box to move the highlight to a specific list item. The first component
of a message name indicates the kind of window this message is destined for, or coming
from. These window types are listed in Table 3.1.</P>
<P>
<H4>Table 3.1&#160;&#160;Windows Message Prefixes and Window Types</H4>
<P>
<TABLE BORDER="1">
	<TR ALIGN="LEFT" VALIGN="TOP">
		<TD ALIGN="LEFT"><B>Prefix</B></TD>
		<TD ALIGN="LEFT"><B>Window Type</B></TD>
	</TR>
	<TR ALIGN="LEFT" VALIGN="TOP">
		<TD ALIGN="LEFT">ABM, ABN		</TD>
		<TD ALIGN="LEFT">Appbar		</TD>
	</TR>
	<TR ALIGN="LEFT" VALIGN="TOP">
		<TD ALIGN="LEFT">ACM, ACN		</TD>
		<TD ALIGN="LEFT">Animation control		</TD>
	</TR>
	<TR ALIGN="LEFT" VALIGN="TOP">
		<TD ALIGN="LEFT">BM, BN		</TD>
		<TD ALIGN="LEFT">Button		</TD>
	</TR>
	<TR ALIGN="LEFT" VALIGN="TOP">
		<TD ALIGN="LEFT">CB, CBN		</TD>
		<TD ALIGN="LEFT">Combo box		</TD>
	</TR>
	<TR ALIGN="LEFT" VALIGN="TOP">
		<TD ALIGN="LEFT">CDM, CDN		</TD>
		<TD ALIGN="LEFT">Common dialog box		</TD>
	</TR>
	<TR ALIGN="LEFT" VALIGN="TOP">
		<TD ALIGN="LEFT">CPL		</TD>

⌨️ 快捷键说明

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