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

📄 ch04.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>

<HEAD>
	<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
	<META NAME="Author" Content="Steph Mineart">
	<TITLE>Ch 4 -- Events</TITLE>
</HEAD>

<BODY 
BACKGROUND="bg1.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/bg1.gif" BGCOLOR="#FFFFFF">

<P ALIGN="CENTER"><IMG SRC="sams.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/sams.gif" WIDTH="75" HEIGHT="24" ALIGN="BOTTOM"
BORDER="0">
<P>
<P ALIGN="CENTER"><A HREF="index-3.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/index.htm"><IMG SRC="toc.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/toc.gif" WIDTH="40" HEIGHT="40"

ALIGN="BOTTOM" ALT="TOC" BORDER="0" NAME="toc4"></A><A HREF="ch03.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch03.htm"><IMG SRC="back-1.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/back.gif"
WIDTH="40" HEIGHT="40" ALIGN="BOTTOM" ALT="BACK" BORDER="0" NAME="toc1"></A><A HREF="ch05.htm" tppabs="http://pbs.mcp.com/ebooks/0672310228/ch05.htm"><IMG
SRC="forward.gif" tppabs="http://pbs.mcp.com/ebooks/0672310228/buttonart/forward.gif" WIDTH="40" HEIGHT="40" 
ALIGN="BOTTOM" ALT="FORWARD" BORDER="0"
NAME="toc2"></A></P>
<H2 ALIGN="CENTER"><FONT COLOR="#000077">Charlie Calvert's C++ Builder Unleashed</FONT></H2>
<P>
<H2 ALIGN="CENTER"><A NAME="Heading1"></A><FONT COLOR="#000077">- 4 -</FONT></H2>
<H2 
ALIGN="CENTER"><A NAME="Heading2"></A><FONT COLOR="#000077">Events</FONT></H2>
<P>In this chapter you take a look at the basic facts about the BCB delegation model.
Events are fundamental to the use of this programming environment, and you will never

be able to do serious work in BCB without understanding them.</P>
<P>Subjects covered in this chapter include

<UL>
	<LI>Using the mouse and the keyboard
	<P>
	<LI>Responding directly to Windows messages such as <TT>WM_KEYDOWN</TT> or 
<TT>WM_MOUSEMOVE</TT>
	<P>
	<LI>Custom event structures such as <TT>TWMMouse</TT> or <TT>TMessage</TT>
	<P>
	<LI>Menus and menu IDs
	<P>
	<LI>Setting up a <TT>WndProc</TT> in a VCL application
	<P>
	<LI>Responding to <TT>WM_COMMAND</TT> messages
</UL>


<P>This chapter is not designed to be difficult, but rather to hit the highlights
of each of these subjects so you can understand how to use events in your own programs.
By the time you are through with this chapter, you should have a thorough 
understanding
of the BCB delegation model and will know how to use events in your own program.
Additional material on events is included in the chapters that cover creating components.
<H3><A NAME="Heading3"></A><FONT COLOR="#000077">Events: The BCB 
Delegation Model</FONT></H3>
<P>The two central ideas behind the type of RAD programming of which BCB partakes
are components and delegation. Components are treated at length in Part IV of this
book, called &quot;Creating Components.&quot; This is 
where I will talk about delegation.</P>
<P>Delegation is an alternative to inheritance. It's a trick to allow you to receive
the same benefits as inheritance but with less work.</P>
<P>Delegation is not entirely original with RAD programming; however, 
it is taken
much further in this paradigm than elsewhere. A part of classic windows programming
that supports delegation is the way you handle standard <TT>WM_COMMAND</TT> messages.</P>
<P>Think for a moment about standard Windows programming as it 
appeared before RAD
rewrote the book on Windows programming. I'm talking the Windows programming of Petzold,
or of my Teach Yourself Windows 95 Programming in 21 Days (Sams Publishing) book.
Suppose that in a standard Windows program you have a button 
that responds to a particular
event, say a message click. You usually handled that click inside the <TT>WM_COMMAND</TT>
section of the window procedure (<TT>WndProc</TT>). Windows was delegating the event
from the button to your <TT>WM_COMMAND</TT> 
handler. In other words, Windows did
not force you to subclass the <TT>button</TT> class in order to respond to clicks
on a button.</P>
<P>This is the central idea behind the delegation model in BCB. In C++Builder, if
you drop a button on a form, you 
can set up an <TT>OnClick</TT> event handler to
handle clicks on the button. The great advantage this system has over the standard
Windows model is ease of use. BCB will create the message handler for you, asking
that you write only the code that 
responds to the event. Specifically, it fills in
the class definition with a declaration for your event in the header:</P>
<PRE><FONT COLOR="#0066FF">class TForm1 : public TForm

{

__published:

  TButton *Button1;

  void __fastcall 
Button1Click(TObject *Sender); // DECLARATION HERE!

private:

public:

  virtual __fastcall TForm1(TComponent* Owner);

};

</FONT></PRE>
<P>And it creates the even handler itself in your CPP file:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall 
TForm1::Button1Click(TObject *Sender)

{

}

</FONT></PRE>
<P>This is what is meant by the delegation model in BCB. What is radical about the
VCL's use of the delegation model is that it appears everywhere. All sorts of components
support the model 
and enable you to use it to do all sorts of things that required
subclassing in standard Windows programming and in OWL or MFC.</P>
<P>One of the primary goals of the delegation model is to allow the main form in
your application to handle code that 
you would have had to use inheritance to handle
in OWL or MFC. In the inheritance model you had to override a constructor to change
the way an object was initialized. In BCB, you just respond to an <TT>OnCreate</TT>
event. If you want to modify the 
things a user can type into an edit control, you
don't have to subclass the control; instead, you just respond to <TT>OnKeyDown</TT>
events.</P>
<P>Delegation is easier than inheritance. It enables neophytes who don't understand
inheritance a way to 
get up to speed quickly. More importantly, it enables programmers
to get their work done quickly without a lot of repetitive typing.</P>
<P>Of course, if you want to use inheritance, it is available. In fact, inheritance
is used all the time in BCB. 
The point is not to eliminate a powerful technique like
inheritance, but to give you an alternative to use in the vast majority of cases
where inheritance is overkill.
<H4><A NAME="Heading4"></A><FONT COLOR="#000077">The Delegation Model and 
Contract-Free
Programming</FONT></H4>
<P>The delegation model supports something called contract-free programming. In some
semiliterate circles this has also been known as &quot;contractless&quot; programming.</P>
<P>The idea behind contract-free 
programming is that there is no contract between
the developer of a component and the user of a component as to what can and can't
be done inside an event handler.</P>
<P>A classic example of a contract-bound program is found in Windows when you 
handle
<TT>WM_KILLFOCUS</TT> message. There are some things you can and cannot do in response
to this message. For example, if you change the focus during your response to this
message, you can crash Windows. There is a contract between you and 
Windows not to
change the focus while responding to this message. Learning all the things you can
and cannot do in response to a message is a long, error-prone, and frustrating process.</P>
<P>BCB supports contract-free programming, which means you 
can do whatever you want
while responding to an event. BCB is religious in pursuit of this goal. In my code,
I strive to achieve this same goal, though I admit that I have been known to cheat.
When I do so, however, I severely limit the usability of 
my components.
<H3><A NAME="Heading5"></A><FONT COLOR="#000077">The Basics of the Delegation Model</FONT></H3>
<P>Event-oriented code is one of the central tenets of Windows programming. Some
rapid- application development environments attempt to hide 
users from this feature
altogether, as if it were something so complicated that most programmers couldn't
understand it. The truth is that event-oriented programming is not, in itself, particularly
complex. However, some features of the way it is 
implemented in Windows can be confusing
under certain circumstances.</P>
<P>BCB gives you full access to the event-oriented substructure that provides Windows
with a high degree of power and flexibility. At the same time, it simplifies and
clarifies 
the way a programmer handles those events. The end result is a system that
gives you complete access to the power of Windows while simultaneously protecting
you from unnecessary complexity.</P>
<P>These next few sections cover the following topics:


<UL>
	<LI>Event-oriented programming basics
	<P>
	<LI>Responding to mouse events or key events
	<P>
	<LI>Accessing the information passed in events
	<P>
	<LI>The basics of sets, which are used frequently in BCB event handlers
	<P>
	<LI>Circumventing 
BCB message handling tools and directly capturing messages
	<P>
	<LI>Creating <TT>WM_COMMAND</TT> handlers and finding the IDs of the components used
	in a program
</UL>

<P>To be really good at programming Windows, you need to be able to look at 
these
subjects from both the perspective of a RAD programmer and of a Windows API programmer.
That is, you need to know the VCL inside out, and you need to know the Windows API
inside out. This chapter concentrates on the VCL side of that equation, 
whereas the
other side is featured in books such as Teach Yourself Windows 95 Programming in
21 Days (Sams Publishing) and Programming Windows (Microsoft Press). Put both perspectives
together and you can go on to create your own VCL components or you 
can design elegant,
well-structured Windows programs.</P>
<P>Before starting, let me reiterate that BCB hides much of the complexity of Windows
programming. However, the developers did not want to prevent programmers from accessing
any portion of the 
Windows API. By the time you finish reading this section of the
chapter, you should be able to see that BCB gives you access to the full range of
power provided by an event- oriented system.
<H4><A NAME="Heading6"></A><FONT COLOR="#000077">BCB 
Events</FONT></H4>
<P>BCB makes it easy to handle keyboard and mouse events. Suppose, for instance,
you wanted to capture left mouse clicks in the main form of your program. Here's
how to get started. Create a new project and name it 
<TT>EVENTS1.MAK</TT>.</P>
<P>In the Object Inspector for the main form, choose the Events Page and double-click
the area to the right of the <TT>OnClick</TT> property. Create the following function:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall 
TForm1::FormClick(TObject *Sender)

{

  MessageDlg(&quot;The delegation model says hello.&quot;, mtInformation,

             TMsgDlgButtons() &lt;&lt; mbOK, 0);

}

</FONT></PRE>
<P>This code tells Windows that a dialog box should appear every time 
the user clicks
the left mouse button in the form. The dialog box is shown in Figure 4.1.<BR>
<BR>
<A NAME="Heading7"></A><A HREF="04ebu01.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/04/04ebu01.jpg">FIGURE 4.1.</A><FONT COLOR="#000077">
</FONT><I>The dialog box displayed by the EVENTS1 program when 
you click the left
mouse button inside the main form.</I></P>
<P><BR>
The previous code presents one of the simplest possible cases of responding to an
event in a BCB program. It is so simple, in fact, that many programmers write this
kind of code 
without ever understanding that they are writing event-oriented code.
In this case, BCB programmers get the event secondhand, because VCL massages the
event before passing it on to the main form. Nonetheless, this is real event-oriented
programming, 
albeit in a very simplified manifestation.</P>
<P>As you saw back in the section on the Windows API, the operating environment notifies
you not only of the event, but of several related bits of information. For instance,
when a mouse- down event is 
generated, a program is informed about where the event
occurred and which button generated the event. If you want to get access to this
kind of relatively detailed information, you should turn to the Events Page for the
form and create an 
<TT>OnMouseDown</TT> handler:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  if (Shift.Contains(ssRight))

  {

    Canvas-&gt;Brush-&gt;Style = 
bsClear;

    Canvas-&gt;TextOut(X, Y, &quot;* Button&quot;);

  }

}

</FONT></PRE>
<P>This method writes text to the form every time the user clicks the right mouse
button. It sets the brush to <TT>bsClear</TT> style to make the background of text

transparent.</P>
<P>To test this method, run the program and click the right mouse button in several
different locations in the form. You'll see that each spot you click is marked, as
shown in Figure 4.2.<BR>
<BR>
<A NAME="Heading8"></A><A 
HREF="04ebu02.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/04/04ebu02.jpg">FIGURE 4.2.</A><FONT COLOR="#000077">
</FONT><I>When you click the right mouse button in the form of the EVENTS1 program,
the location of the event is recorded.</I></P>
<P><BR>
The <TT>Canvas-&gt;TextOut</TT> function prints 
text to the screen at the location
specified by the variables <TT>X</TT> and <TT>Y</TT>. Both of these variables are
supplied to you by BCB, which received them in turn from the operating system. The
<TT>X</TT> variable tells you the column in which 
the mouse was clicked, and the
<TT>Y</TT> variable tells you the row.</P>
<P>As you can see, BCB makes it simple for you to respond to events. Furthermore,
not only mouse events are easy to handle. You can respond to keypresses in a similar
manner. 
For instance, if you create a method for the <TT>OnKeyDown</TT> property
on the Events Page for the form, you can show the user which key was pressed on the
keyboard whenever the EVENTS1 program has the focus:</P>
<PRE><FONT COLOR="#0066FF">void 
__fastcall TForm1::FormKeyDown(TObject *Sender, WORD &amp;Key,

  TShiftState Shift)

{

  MessageDlg(Key, mtInformation, TMsgDlgButtons() &lt;&lt; mbOK, 0);

}

</FONT></PRE>
<P>In the preceding code, the <TT>MessageDlg</TT> function will pop up the 
ASCII
value associated with a keystroke. In other words, BCB and the operating system both
pass you not an actual letter like <TT>A</TT>, <TT>B</TT>, or <TT>C</TT>, but the
number associated with the key you pressed. On PCs, the letter <TT>A</TT> is 
associated
with the number 65. It wouldn't be appropriate for BCB to perform this translation
for you automatically, because some keys, such as the F1 or Enter key, have no letter
associated with them. Later in this chapter you learn how to use 
<TT>OnKeyDown</TT>
events to respond sensibly to keypresses on special keys such as F1, Shift, or Caps
Lock.</P>
<P>Besides <TT>OnKeyDown</TT> events, BCB also lets you respond to keyboard activity
through the <TT>OnKeyPress</TT> event:</P>
<PRE><FONT 
COLOR="#0066FF">void __fastcall TForm1::FormKeyPress(TObject *Sender, char &amp;Key)

{

  AnsiString S(&quot;OnKeyPress: &quot; + AnsiString(Key));

  MessageDlg(S, mtInformation, TMsgDlgButtons() &lt;&lt; mbOK, 0);

}

</FONT></PRE>
<P>You can see 
that this event is similar to an <TT>OnKeyDown</TT> event. The difference
is that the <TT>Key</TT> variable passed to <TT>OnKeyPress</TT> events is already
translated into a <TT>char</TT>. However, <TT>OnKeyPress</TT> events work only for
the 
alphanumeric keys and are not called when special keys are pressed. In short,
the <TT>OnKeyPress</TT> event is the same as a <TT>WM_CHAR</TT> event.</P>
<P>The code for the EVENTS1 program is shown in Listing 4.1. Get the program up and
running and 
take whatever time is necessary to be sure it all makes sense to you.
There is no point in trying to be a Windows programmer if you don't understand events.<BR>
<BR>
<A NAME="Heading9"></A><FONT COLOR="#000077"><B>Listing 4.1. The main form for the

EVENTS1 program.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////

// Copyright (c) 1997 by Charlie Calvert

//

#include &lt;vcl.h&gt;

#pragma hdrstop

#include &quot;Main.h&quot;

#pragma resource &quot;*.dfm&quot;


TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent* Owner)

  : TForm(Owner)

{

}

void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  if (Shift.Contains(ssRight))

  {

    
Canvas-&gt;Brush-&gt;Style = bsClear;

    Canvas-&gt;TextOut(X, Y, &quot;* Button&quot;);

  }

}

void __fastcall TForm1::DelegateMe(TObject *Sender)

{

  MessageDlg(&quot;The menu says hello.&quot;, mtInformation,

             TMsgDlgButtons() 
&lt;&lt; mbOK, 0);

}

void __fastcall TForm1::FormClick(TObject *Sender)

⌨️ 快捷键说明

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