Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

(Ebook - Pdf) Kick Ass Delphi Programming

.pdf
Скачиваний:
300
Добавлен:
17.08.2013
Размер:
5.02 Mб
Скачать

TMyGrid = class(TDrawGrid) protected

procedure SizeChanged(OldColCount, OldRowCount: Longint); override;

end;

{ In unit's implementation... }

procedure TMyGrid.SizeChanged(OldColCount, OldRowCount: Longint); begin

{ Take whatever actions necessary } end;

Overriding SizeChanged provides all the notification we need, but if we want control over the number of columns—for example, if we’re developing a grid that should have no more than three columns—SizeChanged is not a satisfactory place to shoehorn in our veto. By the time SizeChanged is called (note the past tense in the name), the change has already been made. The best we can do then, if ColCount was set to 4, is change it to 3, requiring the whole private process of change to be repeated.

What we want is front end control, and we can get this by redeclaring the ColCount property with our own access methods (see the TMyGrid declaration in Listing 7.10). Our redeclaration of the property will hide our ancestor’s ColCount, so that when a programmer writes

ColCount := AValue;

our own nonvirtual SetColCount access method will be called. As you can see from the SetColCount method in Listing 7.10, we first check to see whether the suggested value for the number of columns is less than or equal to 3. If it is, we make the change.

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

Go!

Keyword

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

Listing 7.10 SETCOLCT.SRC

{A descendant of TDrawGrid that redeclares the ColCount property with new access methods. This lets the descendant component control the number of columns. }

{In unit's interface... }

type

TMyGrid = class(TDrawGrid) private

function GetColCount: LongInt; procedure SetColCount(Value: LongInt);

published

property ColCount: LongInt read GetColCount write SetColCount default 0;

end;

{ In unit's implementation... }

function TMyGrid.GetColCount: LongInt; begin

Result := inherited ColCount; end;

procedure SetColCount(Value: LongInt); begin

if Value <= 3 then inherited ColCount := Value; end;

But how we make the change is perhaps the most interesting part of redeclaring a property. We can’t directly change the FColCount field—and we wouldn’t want to if we

could—because the other adjustments needed in the grid would not get made. We can’t call our ancestor’s SetColCount method—that’s private. And if we write

ColCount := Value;

within our own SetColCount method, we will create endless recursion and crash the stack.

The answer is to use the INHERITED keyword with the property name:

inherited ColCount := Value;

The ability to use INHERITED with an ancestor’s property name is not as well documented as its use with an inherited public or protected method. It’s a pleasant surprise, but it is entirely consistent with Object Pascal’s other pleasant surprises.

Taking Snapshots of the Screen with Delphi

In Delphi, if we want to capture the image of a form’s client area, we can call GetFormImage. But sometimes we want a snapshot of the entire form—title bar, frame, and all. Or we want a snapshot of the entire screen. If we were desperate, we might pop up a message box that says, “Press Print Screen button NOW!” and then figure out a way to get the screen’s mug off the clipboard.

But we’re not that desperate. Combining Delphi canvases with a few GDI functions makes capturing the screen in code a snap. CaptureScreenRect, in Listing 7.11, demonstrates this. It gets the screen’s device context with GetDC(0), and then it copies a rectangular area from that DC to a bitmap’s canvas. To do the copying, it uses BitBlt. The key to using BitBlt—or any GDI function—with Delphi is remembering that a canvas’ Handle is the DC that Windows needs.

Listing 7.11 SCRNCAP.PAS

{ Screen capture functions for Delphi } unit ScrnCap;

interface

uses WinTypes, WinProcs, Forms, Classes, Graphics;

function CaptureScreenRect( ARect: TRect ): TBitmap; function CaptureScreen: TBitmap;

function CaptureClientImage( Control: TControl ): TBitmap; function CaptureControlImage( Control: TControl ): TBitmap;

implementation

{ Use this to capture a rectangle on the screen... } function CaptureScreenRect( ARect: TRect ): TBitmap; var

ScreenDC: HDC; begin

Result := TBitmap.Create; with Result, ARect do

begin

Width := Right - Left; Height := Bottom - Top;

ScreenDC := GetDC( 0 ); try

BitBlt( Canvas.Handle, 0, 0, Width, Height, ScreenDC, Left, Top, SRCCOPY );

finally

ReleaseDC( 0, ScreenDC ); end;

end;

end;

{Use this to capture the entire screen... } function CaptureScreen: TBitmap;

begin

with Screen do

Result := CaptureScreenRect( Rect( 0, 0, Width, Height ));

end;

{Use this to capture just the client area of a form

or control... }

function CaptureClientImage( Control: TControl ): TBitmap; begin

with Control, Control.ClientOrigin do

Result := CaptureScreenRect( Bounds( X, Y, ClientWidth, ClientHeight ));

end;

{ Use this to capture an entire form or control... } function CaptureControlImage( Control: TControl ): TBitmap; begin

with Control do

if Parent = nil then

Result := CaptureScreenRect( Bounds( Left, Top, Width, Height ))

else

with Parent.ClientToScreen( Point( Left, Top )) do Result := CaptureScreenRect( Bounds( X, Y, Width,

Height ));

end;

end.

The remaining screen capture functions in Listing 7.11 cobble up rectangles and farm out the real work to CaptureScreenRect. CaptureScreen throws together a rectangle for the whole screen. CaptureClientImage and CaptureControlImage throw together rectangles for the client area and for the entire area of a control, respectively.

These four functions can be used to capture any arbitrary screen area, as well as the screen images of forms, buttons, memos, combo boxes, and so on. We just tell the little buggers to

say cheese—and free the bitmaps when we’re done.

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

Go!

Keyword

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

Delphi RadioGroup Buttons You Can Disable

When I am designing forms, nothing is quite so comforting as controls that know how to snap into place, spring out to size, and arrange their contents into columns: Hey, I feel as though I’m not fighting the battle alone. And the benefit of these size-wise controls is not just emotional; how many lines of code has a panel’s Align property saved me? Tens? Hundreds? That’s why, when I need to disable individual radio buttons, I am reluctant to heave the springy little RadioGroup control over the side. TRadioGroup automatically arranges its child buttons into columns, spaces them evenly, and lets them be named with one string list.

What it does not do is allow access to individual buttons—and for good reason, I’m sure. But since I trust myself to disable responsibly, I derived an enhanced component from TRadioGroup, as shown in Listing 7.12. TRadioBtnGroup has a new property, ItemEnabled, that lets us get and set the enabled status of individual buttons.

Listing 7.12 RBTNGRPS.PAS

{ A radio group with buttons that can be disabled } unit RBtnGrps;

interface

uses StdCtrls, ExtCtrls;

type

TRadioBtnGroup = class( TRadioGroup ) private

function GetItemEnabled( Index: Integer ): Boolean; procedure SetItemEnabled( Index: Integer; Value: Boolean ); function GetButtons( Index: Integer ): TRadioButton;

protected

function CheckAnyBut( NotThisIndex: Integer ): Boolean; property Buttons[ Index: Integer ]: TRadioButton

read GetButtons; public

property ItemEnabled[ Index: Integer ]: Boolean read GetItemEnabled write SetItemEnabled;

end;

implementation

function TRadioBtnGroup.CheckAnyBut; var

Index: Integer; begin

Result := True;

for Index := NotThisIndex + 1 to Items.Count - 1 do if Buttons[ Index ].Enabled then

begin

Buttons[ Index ].Checked := True; Exit;

end;

for Index := 0 to NotThisIndex - 1 do if Buttons[ Index ].Enabled then begin

Buttons[ Index ].Checked := True; Exit;

end;

Result := False; end;

function TRadioBtnGroup.GetItemEnabled; begin

Result := Buttons[ Index ].Enabled; end;

procedure TRadioBtnGroup.SetItemEnabled; begin

if ( not Value ) and ( Index = ItemIndex ) and Buttons[ Index ].Checked and

( not CheckAnyBut( Index )) then ItemIndex := -1;

Buttons[ Index ].Enabled := Value; end;

function TRadioBtnGroup.GetButtons; begin

Result := Components[ Index ] as TRadioButton; end;

end.

Internally, TRadioBtnGroup uses the GetButtons method to gain access to its radio buttons. GetButtons relies on the fact that, since a radio group owns its child buttons, it holds them in its Components array. All GetButtons does is index into the Components array and safely typecast the result.

The new control tries its best to be an intelligent helper. If a checked button is disabled, the

control tries to check another button; if all the buttons are disabled, it unchecks all the buttons. Depending on your needs, you might want to change this latter behavior.

Products | Contact Us | About Us | Privacy | Ad Info | Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Kick Ass Delphi Programming

Go!

Keyword

(Publisher: The Coriolis Group)

Author(s): Don Taylor, Jim Mischel, John Penman, Terence Goggin

ISBN: 1576100448

Publication Date: 09/01/96

Search this book:

Go!

-----------

CHAPTER 8

Animated Screen Savers in Delphi

RAY KONOPKA

Hooking the Application’s OnIdle Event

Windows 95 Callback Functions

A Combo Box for Color Selection

Special Project File Modifications

Anything you can do with the Windows API, you can do in Delphi. How about a screen saver? Fear not the Windows Callback, and kiss MakeProcInstance goodbye!

Unlike many other visual development tools, Delphi provides complete access to the Windows

API. Yes, the VCL does encapsulate much of this API, but not all of it. This chapter investigates how Delphi applications can take advantage of the Windows API. To demonstrate the process, we’re going to create a screen saver.

Figure 8.1 shows a picture of the screen saver in action. The basic scheme is that a laser beam (okay, a line) draws out the Def Leppard logo and then erases it. I selected the logo of my favorite band, but you could use any logo you want. All you need to do is determine the coordinates of the line segments that define the path of the laser.

FIGURE 8.1 The Def Leppard screen saver.

Secrets of the Main Form

The heart of the screen saver lies in the LaserFrm form file. Listing 8.1 shows the source code for the unit embodying the form file. This form file defines the TFrmLaser form class, which

represents the main window on which the laser beam will draw the logo.

Listing 8.1 LASERFRM.PAS

unit LaserFrm;

interface

uses

Messages, WinTypes, WinProcs, Classes, Graphics, Controls, Forms, DLPoints, SvrUtils;

type

 

 

TFrmLaser =

class(TForm)

 

procedure

FormCreate(Sender: TObject);

procedure

FormClose( Sender: TObject;

 

var

Action: TCloseAction);

procedure

FormKeyDown( Sender: TObject; var Key: Word;

 

Shift: TShiftState);

procedure

FormMouseDown(

Sender: TObject; Button: TMouseButton;

 

 

Shift: TShiftState; X, Y: Integer);

procedure

FormMouseMove(

Sender: TObject; Shift: TShiftState;

 

 

X, Y: Integer);

private

FMousePt : TPoint; FDone : Boolean; FOriginPoint : Longint;

FOrigins : array[ TLaserOrigin ] of Longint; FCurrPoint : Integer;

FFirstPass : Boolean; FGettingPassword : Boolean; FOrigX : Integer;

FOrigY : Integer;

procedure IdleProc( Sender : TObject; var Done : Boolean ); procedure Animate;

procedure CursorOff; procedure CursorOn; procedure PopulateOrigins; procedure GetPassword;

procedure SetTopMost( TopMost : Boolean ); end;

var

FrmLaser: TFrmLaser;

implementation

{$R *.DFM}

uses

GetPWFrm, MMSystem;

const

Offset = 25; { Distance from Screen Edge of Laser Source }