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

📄 ch07.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:

  
TMenuItem *Colors1;

  TMenuItem *Brush1;

  TMenuItem *Pen1;

  TPanel *Panel1;

  TSpeedButton *SpeedButton1;

  TSpeedButton *SpeedButton2;

  TSpeedButton *SpeedButton3;

  TSpeedButton *SpeedButton4;

  TMenuItem *Lines1;

  TColorDialog 
*ColorDialog1;

  TSpeedButton *SpeedButton5;

  void __fastcall FormMouseDown(TObject *Sender, TMouseButton Button,

                                TShiftState Shift, int X, int Y);

  void __fastcall FormMouseUp(TObject *Sender, TMouseButton 
Button,

                              TShiftState Shift, int X, int Y);

  void __fastcall FormMouseMove(TObject *Sender, TShiftState Shift, int X,

                                int Y);

  void __fastcall SpeedButton1Click(TObject *Sender);

  
void __fastcall Brush1Click(TObject *Sender);

  void __fastcall Pen1Click(TObject *Sender);

  void __fastcall SpeedButton5Click(TObject *Sender);

private:

  TRect FShapeRect;

  TColor FPenColor;

  TColor FBrushColor;

  bool FDrawing;

  
TCurrentShape FCurrentShape;

  int FPenThickness;

  void __fastcall DrawShape();

public:

  virtual __fastcall TForm1(TComponent* Owner);

};

extern TForm1 *Form1;

#endif

</FONT></PRE>
<H3 ALIGN="CENTER"><FONT COLOR="#0066FF"></FONT></H3>
<P><A 
NAME="Heading8"></A><FONT COLOR="#000077"><B>Listing 7.2. The main form for
the DrawShapes program shows how to draw shapes on a canvas.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////

// Main.cpp

// DrawShapes 
Example

// Copyright (c) 1997 by Charlie Calvert

//

#include &lt;vcl\vcl.h&gt;

#pragma hdrstop

#include &quot;Main.h&quot;

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

TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

  
FDrawing= False;

  FCurrentShape = csRectangle;

  FBrushColor = clBlue;

  FPenColor = clYellow;

  FPenThickness = 1;

}

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

                                      TShiftState 
Shift, int X, int Y)

{

  FShapeRect.Left = X;

  FShapeRect.Top = Y;

  FShapeRect.Right = - 32000;

  FDrawing = True;

}

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

                                    TShiftState 
Shift, int X, int Y)

{

  FDrawing = False;

  FShapeRect.Right = X;

  FShapeRect.Bottom = Y;

  Canvas-&gt;Pen-&gt;Mode = pmCopy;

  DrawShape();

}

void __fastcall TForm1::DrawShape()

{

  Canvas-&gt;Brush-&gt;Color = FBrushColor;

  
Canvas-&gt;Pen-&gt;Color = FPenColor;

  Canvas-&gt;Pen-&gt;Width = FPenThickness;

  switch (FCurrentShape)

  {

    case csLine:

      Canvas-&gt;MoveTo(FShapeRect.Left, FShapeRect.Top);

      Canvas-&gt;LineTo(FShapeRect.Right, 
FShapeRect.Bottom);

      break;

    case csRectangle:

      Canvas-&gt;Rectangle(FShapeRect.Left, FShapeRect.Top,

                        FShapeRect.Right, FShapeRect.Bottom);

      break;

    case csEllipse:

      
Canvas-&gt;Ellipse(FShapeRect.Left, FShapeRect.Top,

                      FShapeRect.Right, FShapeRect.Bottom);

      break;

    default:

      ;

  }

}

void __fastcall TForm1::FormMouseMove(TObject *Sender,

                                      
TShiftState Shift, int X, int Y)

{

  if (FDrawing)

  {

    Canvas-&gt;Pen-&gt;Mode = pmNotXor;

    if (FShapeRect.Right != -32000)

      DrawShape();

    FShapeRect.Right = X;

    FShapeRect.Bottom = Y;

    DrawShape();

  }

}

void 
__fastcall TForm1::SpeedButton1Click(TObject *Sender)

{

  FCurrentShape = TCurrentShape(dynamic_cast&lt;TSpeedButton *&gt;(Sender)-&gt;Tag);

}

void __fastcall TForm1::Brush1Click(TObject *Sender)

{

  ColorDialog1-&gt;Color = FBrushColor;

  if 
(ColorDialog1-&gt;Execute())

    FBrushColor = ColorDialog1-&gt;Color;

}

void __fastcall TForm1::Pen1Click(TObject *Sender)

{

  ColorDialog1-&gt;Color = FPenColor;

  if (ColorDialog1-&gt;Execute())

    FPenColor = ColorDialog1-&gt;Color;

}


void __fastcall TForm1::SpeedButton5Click(TObject *Sender)

{

  FPenThickness = dynamic_cast&lt;TSpeedButton *&gt;(Sender)-&gt;Tag;

}

</FONT></PRE>
<P>This program enables you to draw lines, rectangles, and ellipses on the main form
of the 
application. You can select the type of shape you want to work with through
the menus or by clicking on speed buttons. The program also lets you set the color
of the shapes you want to draw and specify the width and color of the border around
the 
shape.
<H4><A NAME="Heading9"></A><FONT COLOR="#000077">Pens and Brushes</FONT></H4>
<P>When setting the color of a shape, you need to know that the filled area inside
a shape gets set to the color of the current <TT>Brush</TT> for the canvas. The 
line
that forms the border for the shape is controlled by the current <TT>Pen</TT>.</P>
<P>Here is how to set the current color and width of the <TT>Pen</TT>:</P>
<PRE><FONT COLOR="#0066FF">Canvas-&gt;Pen-&gt;Color = clBlue;

</FONT></PRE>
<PRE><FONT 
COLOR="#0066FF">

Canvas-&gt;Pen-&gt;Width = 5;

</FONT></PRE>
<P>If you want to change the color of the <TT>Brush</TT>, you can write the following
code:</P>
<PRE><FONT COLOR="#0066FF">

Canvas-&gt;Brush-&gt;Color = clYellow;

</FONT></PRE>
<P>I 
don't work with it in this program, but you can assign various styles to a <TT>Brush</TT>,
as defined by the following enumerated type:</P>
<PRE><FONT COLOR="#0066FF">TBrushStyle { bsSolid, bsClear, bsHorizontal, bsVertical,

  bsFDiagonal, 
bsBDiagonal, bsCross, bsDiagCross };

</FONT></PRE>
<P>By default, a <TT>Brush</TT> has the <TT>bsSolid</TT> type.</P>
<P>To set the style of a <TT>Brush</TT>, you would write code that looks like this:</P>
<PRE><FONT 
COLOR="#0066FF">Canvas-&gt;Brush-&gt;Style = bsSolid;

</FONT></PRE>
<P><TT>Brush</TT>es also have <TT>Color</TT> and <TT>Bitmap</TT> properties. The
<TT>Bitmap</TT> property can be set to a small external bitmap image that defines
the pattern for 
<TT>Brush</TT>.</P>
<P>There is only one method of the <TT>TBrush</TT> object that you would be likely
to use. This method is called <TT>Assign</TT>, and it is used when you want to copy
the characteristics of one brush to another brush.</P>

<P><TT>Pen</TT>s have all the same properties as <TT>Brush</TT>es, but they add a
<TT>Width</TT> and <TT>Mode</TT> property. The <TT>Width</TT> property defines the
width of the <TT>Pen</TT> in pixels, and the <TT>Mode</TT> property defines the type

of operation to use when painting the <TT>Pen</TT> to the screen. These logical operations
will be discussed further in just a few moments.
<H4><A NAME="Heading10"></A><FONT COLOR="#000077">Rubber Banding</FONT></H4>
<P>Before reading this section, 
fire up the DrawShapes program and practice drawing
ellipses and rectangles onscreen so you can see how the rubber-band technique works.
If for some reason you can't run the DrawShapes program, open up Windows Paint and
draw some squares or circles by 
first clicking the appropriate icon from the Tools
menu. Watch the way these programs create an elastic square or circle that you can
drag around the desktop. Play with these shapes as you decide what dimensions and
locations you want for your 
geometric figures.</P>
<P>These tools appear to be difficult for a programmer to create, but thanks to the
Windows API, the code is relatively trivial. Following are the main steps involved,
each of which is explained in-depth later in this section:


<DL>
	<DD><B>1.</B> When the user clicks the left mouse button, DrawShapes &quot;memorizes&quot;
	the x and y coordinates of the <TT>WM_LBUTTONDOWN</TT> event.<BR>
	<BR>
	<B>2. </B>As the user drags the mouse across the screen with the left button 
still
	down, DrawShapes draws a square or circle each time it gets a <TT>WM_MOUSEMOVE</TT>
	message. Just before painting each new shape, the program blanks out the previous
	square or circle. The dimensions of the new shape are calculated by 
combining the
	coordinates of the original <TT>WM_LBUTTONDOWN</TT> message with the current coordinates
	passed in the <TT>WM_MOUSEMOVE</TT> message.<BR>
	<BR>
	<B>3. </B>When the user generates a <TT>WM_LBUTTONUP</TT> message, DrawShapes paints
	the 
final shape in the colors and pen size specified by the user.
</DL>

<P>Although this description obviously omits some important details, the outlines
of the algorithm should take shape in your mind in the form of only a few relatively
simple, logical 
strokes. Things get a bit more complicated when the details are mulled
over one by one, but the fundamental steps should be relatively clear.

<DL>
	<DT></DT>
</DL>



<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>In the 
previous numbered list, I
	give the names of the messages that generate VCL events. For instance, a <TT>WM_LBUTTONDOWN</TT>
	message generates an <TT>OnMouseDown</TT> event, the <TT>WM_MOUSEMOVE</TT> message
	generates an <TT>OnMouseMove</TT> event, 
and so on. I'm referring to the underlying
	messages because it is a good idea to remember the connection between VCL events
	and their associated Windows messages. 
<HR>


</BLOCKQUOTE>

<P>Zooming in on the details, here's a look at the response to 
a <TT>WM_LBUTTONDOWN</TT>
message:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,

  TShiftState Shift, int X, int Y)

{

  FShapeRect.Left = X;

  FShapeRect.Top = Y;

  FShapeRect.Right = - 
32000;

  FDrawing = True;

}

</FONT></PRE>
<P><TT>FormMouseDown</TT> saves the location on which the mouse was clicked in the
first two fields of a <TT>TRect</TT> structure called <TT>FShapeRect</TT>. <TT>FShapeRect</TT>
is declared as a field of 
<TT>TForm1</TT>. I set the <TT>Right</TT> field of the
<TT>TRect</TT> structure to a large negative number so I know that this is the first
time that I need to start tracking the user's mouse movements. This is necessary
because the very first shape I 
draw needs to be treated as a special case.</P>
<P>The last thing done in the <TT>FormMouseDown</TT> method is to set a private variable
of <TT>TForm1</TT> called <TT>FDrawing</TT> to <TT>True</TT>. This lets the program
know that the user has started 
a drawing operation.</P>
<P>After the left mouse button is pressed, the program picks up all <TT>WM_MOUSEMOVE</TT>
messages that come flying into <TT>DrawShape</TT>'s ken:</P>
<PRE><FONT COLOR="#0066FF">void __fastcall TForm1::FormMouseMove(TObject 
*Sender,

                                      TShiftState Shift, int X, int Y)

{

  if (FDrawing)

  {

    Canvas-&gt;Pen-&gt;Mode = pmNotXor;

    if (FShapeRect.Right != -32000)

      DrawShape();

    FShapeRect.Right = X;

    
FShapeRect.Bottom = Y;

    DrawShape();

  }

}

</FONT></PRE>
<P>The first line of the function uses one of several possible techniques for checking
to see if the left mouse button is down. If the button isn't down, the function ignores
the message. 
If it is down, the function gets the device context, sets the <TT>Pen</TT>'s
drawing mode to <TT>pmNotXor</TT>, memorizes the current dimensions of the figure,
draws it, and releases the device context.</P>
<P>The <TT>Mode</TT> property of a 
<TT>TPen</TT> object sets the current drawing
mode in a manner similar to the way the last parameter in <TT>BitBlt</TT> sets the
current painting mode. You can achieve the same effect by directly calling the Windows
API function called 
<TT>SetROP2</TT>. In this case, <TT>DrawShape</TT> uses the logical
<TT>XOR</TT> and <TT>NOT</TT> operations to <TT>blit</TT> the elastic image to the
screen. This logical operation is chosen because it paints the old shape directly
on top of the 
original image, thereby effectively erasing each shape:

⌨️ 快捷键说明

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