How to write custom event that fires when DBGrid.SelectedRows.Count changes? - delphi

How to write a custom event that fires when DBGrid.SelectedRows.Count changes?
I need this events to conditionally show/hide a panel when the selected rows in a DBGrid are [zero | one] or more than one.
Since now I'm using the following code, but IMO coding a custom event is more appropriate here:
TForm3.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; Field: TField; State: DBGridDrawState);
begin
Panel1.Visible := TDBGrid(Sender).SelectedRows.Count > 1;
end;

To catch all events changing the internal Bookmarklist yoe will have to override
LinkActive
KeyDown
MouseDown
above example just as interposer class, could be changed to a new component.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, DBGrids, DB, ADODB;
type
TDBGrid=Class(DBGrids.TDBGrid)
private
FOnSelectionChanged: TNotifyEvent;
procedure LinkActive(Value: Boolean); override;
procedure KeyDown(var Key: Word; Shift: TShiftState);override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
published
published
property OnSelectionChanged:TNotifyEvent read FOnSelectionChanged write FOnSelectionChanged;
End;
TForm1 = class(TForm)
ADODataSet1: TADODataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Button1: TButton;
procedure MyOnSelectionChanged(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
uses unit3;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
AdoDataset1.Active := Not AdoDataset1.Active;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DBGrid1.OnSelectionChanged := MyOnSelectionChanged;
end;
procedure TForm1.MyOnSelectionChanged(Sender: TObject);
begin
Caption := IntToStr(TDBGrid(Sender).SelectedRows.Count);
end;
{ TDBGrid }
procedure TDBGrid.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited;
if Assigned(FOnSelectionChanged) then FOnSelectionChanged(self);
end;
procedure TDBGrid.LinkActive(Value: Boolean);
begin
inherited;
if Assigned(FOnSelectionChanged) then FOnSelectionChanged(self);
end;
procedure TDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited;
if Assigned(FOnSelectionChanged) then FOnSelectionChanged(self);
end;
end.

Related

delphi 7 - using NotXor penmode for resizing rectangles

I made an application that lets you create a rectangle and resize it however you want but it has a problem.
Whenever I want to draw a new rectangle on an existing one happens.
Here is the code for the application :
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
Button1: TButton;
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Button1Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
xstart,ystart,oldx,oldy,click1,lastx,lasty,copyrect_click:integer;
in_workspace,click_bol,copyrect_bol:boolean;
destrect,sourcerect:trect;
implementation
{$R *.dfm}
procedure TForm1.FormActivate(Sender: TObject);
begin
image1.Canvas.pen.Width:=10;
image1.Canvas.Pen.style:=psSolid;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
click_bol:=true;
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if click_bol then
begin
xstart:=x;
ystart:=y;
oldx:=x;
oldy:=y;
image1.Canvas.pen.mode:=pmnotxor;
image1.canvas.rectangle(xstart,ystart,oldx,oldy);
click1:=click1+1;
in_workspace:=true;
if click1 mod 2=0 then
begin
image1.canvas.Pen.mode:=pmCopy;
image1.Canvas.Rectangle(xstart,ystart,x,y);
in_workspace:=false;
end;
end;
end;
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if (in_workspace=true) and (click_bol=true) then
begin
image1.canvas.Rectangle(xstart,ystart,oldx,oldy);
image1.canvas.Rectangle(xstart,ystart,x,y);
oldx:=x;
oldy:=y;
end;
end;
end.
I suspect it's because of the NotXor penmode and as you can see from the code I tried to change it to Copy penmode when it draws the actual rectagle but to no avail.
How can I improve this code in order not to have the rectangles change color then I draw them one on another?
Firstly I don't think that you really understand what you are doing and why it works (sort of). I think that you have dug up some code from somewhere and are trying to migrate it. All those global variables are a bad sign.
(You also have no mouse-up function - so what you have published will never produce the image you have shown.)
So, what does it do? Well, the canvas background is white and the pen is black (these are default values that you don't change) so if you XORed them the result would actually be white - it would appear to do nothing (unless you changed the pen colour to white), and the NotXOR makes it black. The original program I am guessing used XOR as that was more normal in older programs.
However, these days graphics have greatly improved, and, as David Heffernan says, better to just draw on the old background, and as you progress your program to using colours, this will become more important.
This shows the equivalent to what you are trying to achieve using this method.
Notice that there is much less code. I have removed the button click - it is just a waste of time. Better to put that in the mouse-down event. I have also not dealt with right mouse click etc. (but then, neither did you).
unit Unit10;
interface
uses
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, Vcl.ComCtrls,
Vcl.Grids, Vcl.Buttons, VCL.ExtCtrls,
System.Classes;
type
TForm1 = class(TForm)
Image1: TImage;
procedure FormActivate(Sender: TObject);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
fSave : TPicture;
xstart,ystart:integer;
click_bol:boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormActivate(Sender: TObject);
begin
fSave := TPicture.Create;
image1.Canvas.pen.Width:=10;
image1.Canvas.Pen.style:=psSolid;
end;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
xstart:=x;
ystart:=y;
fSave.Assign( image1.Picture);
click_bol:=true;
end;
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if Click_bol then
begin
image1.Picture.Assign( fSave );
image1.Canvas.pen.Width:=10;
image1.Canvas.Pen.style:=psSolid;
image1.Canvas.Brush.Style := bsClear;
image1.Canvas.Rectangle(xstart,ystart,x,y);
end;
end;
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
click_bol := FALSE;
end;
initialization
end.

calling delphi procedure as method

Here is my simple code which compiles well, but raise Access Violation. It enters MD procedure and debugger displays some X and Y value, but after exiting procedure AV happens. Hope someone can help.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Controls, Forms, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
form1.caption:= inttostr(x)+ ' '+ inttostr(y);
end;
procedure TForm1.FormCreate(Sender: TObject);
function MakeMethod(data, code: pointer): TMethod;
begin
result.Data:= data;
result.Code:= code;
end;
begin
panel1.OnMouseDown:= TMouseEvent(MakeMethod(nil, #MD));
end;
end.
Thanks
MD signature should include additional hidden parameter; it solves AV issue.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure MD(Instance, Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
form1.caption:= inttostr(x)+ ' '+ inttostr(y);
end;
procedure TForm1.FormCreate(Sender: TObject);
function MakeMethod(data, code: pointer): TMethod;
begin
result.Data:= data;
result.Code:= code;
end;
begin
panel1.OnMouseDown:= TMouseEvent(MakeMethod(nil, #MD));
end;
end.
Try making MD a member of your form class. Edit your example the following way:
In the class definition:
type
TForm1 = class(TForm)
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
procedure MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
end;
Later in your code make sure to enter the owner of the MD method like so:
procedure TForm1.MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
Finally, when assigning this eventhandler to your component, all you have to do is:
panel1.OnMouseDown:= MD;
I don't know what your intention was, but that is how you take care of eventhandlers at run time.

Delphi 6 Escape key not working

I'm experiencing a weird issue with trapping the escape key in our main application. I created a simple test form to see what might be going wrong, since pressing the escape key was previously working. So far, it's still not working and I'm unsure why.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure Button2KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure OnAppMessage(var Msg: TMsg; var Handled: Boolean);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Msg.message = WM_KeyDown then
showmessage('MSG');
end;
procedure TForm1.Button1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key = VK_ESCAPE then
showmessage('ESC');
end;
procedure TForm1.Button2KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key = VK_ESCAPE then
showmessage('ESC');
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key = vk_escape then
Button1Click(sender);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage('Button1Click');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := OnAppMessage;
button1.Cancel := True; // set at design time as well
self.KeyPreview := True; // set at design time as well
end;
end.
For some reason when pressing escape, it doesn't break on the point I placed in button1.OnKeyDown or even for the Application message WM_KEYDOWN -- all other keys break here. I tested my keyboard just to make sure the key was functioning and it's good.
Is there something that might be causing this or that I'm doing wrong?
Thanks.
Add this to your component's class:
procedure HandleDlgCode(var Msg:TMessage); message WM_GETDLGCODE;
and then in the implementation section:
procedure TComponentClass.HandleDlgCode(var Msg:TMessage);
var
M: PMsg;
begin
Msg.Result := DLGC_WANTALLKEYS or DLGC_WANTESCAPE or DLGC_WANTCHARS or DLGC_HASSETSEL;
if Msg.lParam <> 0 then
begin
M := PMsg(Msg.lParam);
case M.message of
WM_KEYESCAPE, WM_CHAR:
begin
Perform(M.message, M.wParam, M.lParam);
Msg.Result := Msg.Result or DLGC_WANTMESSAGE;
end;
end;
end
else
Msg.Result := Msg
end;
This is because you set the Cancel property for Button1 to True. Comment the line:
button1.Cancel := True;
and you will be able to catch Escape key. These wo ar mutualy exclusive.
Try rebooting first. It fixed the issue.

User moving Shape at run time

I have a unit called MachineShapes, with a type TShape on it. I am trying to get it so when a user clicks on shape they can move it. I think iam close but got a little confused. Thanks for any help
MachineShapes
unit MachineShape;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, extctrls,myDataModule,Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TMachine = class(TShape)
private
{ Private declarations }
FOnMouseDown : TNotifyEvent;
FOnMouseUp: TNotifyEvent;
FonMouseMove: TNotifyEvent;
procedure ControlMouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure ControlMouseMove(Sender: TObject;
Shift: TShiftState;
X, Y: Integer);
procedure ControlMouseUp(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
private
inReposition : boolean;
oldPos : TPoint;
Protected
procedure DoMouseDown; virtual;
procedure DoMouseUp; Virtual;
procedure DoMouseMove; virtual;
Published
property OnMouseDown: TNotifyEvent Read FOnMouseDown Write fOnMouseDown;
property OnMouseMove: TNotifyEvent Read FOnMouseMove write fOnMouseMove;
Property onMouseUp : TNotifyEvent Read FOnMouseUp write FOnMouseUp;
public
{ Public declarations }
end;
implementation
uses
deptlayout;
procedure TMachine.ControlMouseMove(Sender: TObject; Shift: TShiftState; X: Integer; Y: Integer);
const
minWidth = 20;
minHeight = 20;
var
newPos: TPoint;
frmPoint : TPoint;
begin
if inReposition then
begin
with TWinControl(Sender) do
begin
GetCursorPos(newPos);
Screen.Cursor := crSize;
Left := Left - oldPos.X + newPos.X;
Top := Top - oldPos.Y + newPos.Y;
oldPos := newPos;
end;
end;
end;
procedure TMachine.ControlMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer);
begin
if inReposition then
begin
Screen.Cursor := crDefault;
ReleaseCapture;
inReposition := False;
end;
end;
procedure TMachine.ControlMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer);
begin
inReposition:=True;
SetCapture(TWinControl(Sender).Handle);
GetCursorPos(oldPos);
end;
procedure tmachine.DoMouseDown;
begin
if assigned(fonmousedown) then
fonmousedown(self);
end;
procedure tmachine.DoMouseUp;
begin
if assigned(fonmouseup) then
fonmouseup(self);
end;
procedure tmachine.domousemove;
begin
if assigned(fonmousemove) then
fonmousemove(self);
end;
end.
How i call it..
procedure TFGetZoneDept.CreateShape(Sender: TObject);
var
machine : TMachine;
begin
//creates the shape
machine := MachineShape.TMachine.Create(fdeptlayout); //form to create shape on
machine.Parent := fdeptlayout; //form to add shape to
machine.OnMouseDown := machinemouseDown;
machine.OnMouseUp := machinemouseUp;
machine.OnMouseMove:= machinemouseMove;
end;
procedure TFGetZoneDept.MachineMouseDown(Sender: TObject);
var
machine: TMachine;
begin
machine := Sender as TMachine;
end;
procedure TFGetZoneDept.MachineMouseUp(Sender: TObject);
var
machine: TMachine;
begin
machine := Sender as TMachine;
end;
procedure TFGetZoneDept.machineMouseMove(Sender: TObject);
var
machine: TMachine;
begin
machine := sender as Tmachine;
end;
A shape is no Wincontrol and has no handle you could do something tike that....
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TMachine=Class(TShape)
private
FX,FY:Integer;
Procedure MyMouseDown(var msg:TWMLButtonDown);message WM_LButtonDown;
Procedure MyMouseMove(var msg:TWMMouseMove);message WM_MouseMove;
End;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
FX,FY:Integer;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TMachine }
procedure TMachine.MyMouseDown(var msg: TWMLButtonDown);
begin
inherited;
FX := msg.XPos;
FY := msg.YPos;
end;
procedure TMachine.MyMouseMove(var msg: TWMMouseMove);
begin
inherited;
if ssLeft in KeysToShiftState(msg.Keys) then
begin
Left := Left+ msg.XPos -FX;
Top := Top + msg.YPos -FY;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
With TMachine.Create(self) do
begin
Parent := Self;
Width := 200;
Height := 200;
end;
end;
end.

How to add more objects to my form without adding the same amount of code

I have been making a small game for fun. In the game you are a small spaceship(an image) that shoots lazer beams(shape) at an object(panel). At this moment u can only fire one lazer beam at a time because there is only one lazer beam(shape) and there is only one object(panel) to shoot. So with the coding I have I would like to know how I can add more lazer beams and objects but especially lazer beams because I don't want to repeat the procedures for each lazer beam and for each panel.
Here is the code.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, jpeg;
type
TForm1 = class(TForm)
Panel1: TPanel;
Timer1: TTimer;
Timer2: TTimer;
Button1: TButton;
Shape1: TShape;
Timer3: TTimer;
Image1: TImage;
procedure Timer2Timer(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
procedure Timer3Timer(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
procedure StartPanelAnimation1;
procedure DoPanelAnimationStep1;
function PanelAnimationComplete1: Boolean;
procedure Startlazeranimation1;
procedure DolazeranimationStep1;
{ Public declarations }
end;
var
Form1: TForm1;
implementation
var key : char;
{$R *.dfm}
{ TForm1 }
{ TForm1 }
procedure TForm1.DoPanelAnimationStep1;
begin
Panel1.Top := Panel1.Top+1;
end;
function TForm1.PanelAnimationComplete1: Boolean;
begin
Result := Panel1.Top=512;
end;
procedure TForm1.StartPanelAnimation1;
begin
Panel1.Top := 0;
Timer1.Interval := 1;
Timer1.Enabled := True;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
begin
DoPanelAnimationStep1;
if PanelAnimationComplete1 then
StartPanelAnimation1;
if (shape1.Top < panel1.Top) and (shape1.Left < panel1.Left+104) and (shape1.Left > panel1.Left) then
begin
startpanelanimation1;
sleep(10);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
button1.Hide;
key := 'a';
timer2.Enabled := true;
StartPanelAnimation1;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
shape1.Visible := false;
timer3.Enabled := false;
timer2.Enabled := false;
end;
procedure TForm1.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
begin
image1.Left := image1.Left-10;
end;
procedure TForm1.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
begin
image1.Left := image1.Left+10;
end;
procedure TForm1.DolazeranimationStep1;
begin
shape1.Top := shape1.Top-10;
end;
procedure TForm1.Startlazeranimation1;
begin
shape1.Top := image1.Top;
shape1.Left := image1.Left+55;
shape1.Visible := true;
Timer3.Interval := 1;
Timer3.Enabled := True;
end;
procedure TForm1.Timer3Timer(Sender: TObject);
var k : integer;
begin
DolazeranimationStep1;
if (shape1.Top < panel1.Top) and (shape1.Left < panel1.Left+104) and (shape1.Left > panel1.Left) or (shape1.Top=clientheight) then
begin
timer3.Enabled := false;
shape1.Visible := false;
for k := 1 to 5 do
sleep(1);
begin
application.ProcessMessages;
end;
shape1.Top := 0;
shape1.Left := 0;
end;
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
shape1.Show;
startlazeranimation1;
end;
end.
(The above is the old code)
I have successfully done what Stijn Sanders suggested. But now in this if
if (Shape1.top < panel1.Top) and (shape1.Left < panel1.Left+104) and (shape1.Left > panel1.Left) then
never tests true because shape1 never passes panel1 it, only the shape created on on click passes the panel.
So is there another way to test if the shape is at the pnael.
Not all components need to be created at design time. At run-time, for example using a TTimer and its event, you can call TShape.Create(Self); to have an extra shape. Keep the reference to the resulting value somewhere convenient, for example a (dynamic) array, and remember to set MyShape.Parent:=Self; or MyShape.Parent:=Panel1; so the system knows when and where to display this new control.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
const
MaxRays=100;
RayStep=8;
type
TForm1 = class(TForm)
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
Rays:array[0..MaxRays-1] of TShape;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
i:integer;
begin
for i:=0 to MaxRays-1 do Rays[i]:=nil;
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
i:integer;
begin
i:=0;
while (i<MaxRays) and (Rays[i]<>nil) do inc(i);
if i<MaxRays then
begin
Rays[i]:=TShape.Create(Self);
Rays[i].Shape:=stEllipse;
Rays[i].Pen.Color:=clRed;
Rays[i].Pen.Style:=psSolid;
Rays[i].Brush.Color:=clYellow;
Rays[i].Brush.Style:=bsSolid;
Rays[i].SetBounds(X-4,Y-20,9,41);
Rays[i].Parent:=Self;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i:integer;
begin
for i:=0 to MaxRays-1 do
if Rays[i]<>nil then
begin
Rays[i].Top:=Rays[i].Top-RayStep;
if Rays[i].Top<0 then FreeAndNil(Rays[i]);
end;
end;
end.
Create your objects dynamically at runtime and keep track of them in a list, then you can loop through the list when needed, eg:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, jpeg;
type
TForm1 = class(TForm)
PanelTimer: TTimer;
Button1: TButton;
LazerTimer: TTimer;
Image1: TImage;
procedure PanelTimerTimer(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
procedure LazerTimerTimer(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
Lazers: TList;
Panels: TList;
procedure StartPanelAnimation;
procedure StartLazerAnimation;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.StartPanelAnimation;
var
Panel: TPanel;
begin
Panel := TPanel.Create(Self);
Panel.Parent := Self;
Panel.Top := 0;
// set other Panel properties as needed...
Panel.Visible := True;
Panels.Add(Panel);
if not PanelTimer.Enabled then
begin
PanelTimer.Interval := 1;
PanelTimer.Enabled := True;
end;
end;
procedure TForm1.PanelTimerTimer(Sender: TObject);
var
k: Integer;
Panel: TPanel;
begin
for k := 0 to Panels.Count-1 do
begin
Panel := TPanel(Panels[k]);
Panel.Top := Panel.Top + 1;
if Panel.Top = 512 then
Panel.Top := 0;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
StartPanelAnimation1;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Lazers := TList.Create;
Panels := TList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Lazers.Free;
Panels.Free;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
PanelTimer.Enabled := False;
LazerTimer.Enabled := False;
end;
procedure TForm1.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
begin
Image1.Left := Image1.Left - 10;
end;
procedure TForm1.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
begin
Image1.Left := Image1.Left + 10;
end;
procedure TForm1.StartLazerAnimation;
var
Lazer: TShape;
begin
Lazer := TShape.Create(Self);
Lazer.Parent := Self;
// set Lazer properties as needed...
Lazer.Top := Image1.Top;
Lazer.Left := Image1.Left + 55;
Lazer.Visible := True;
Lazers.Add(Lazer);
if not Lazer.Enabled then
begin
Lazer.Interval := 1;
Lazer.Enabled := True;
end;
end;
procedure TForm1.LazerTimerTimer(Sender: TObject);
var
k, m : integer;
Lazer: TShape;
Panel: TPanel;
PanelHit: Boolean;
begin
k := 0;
while k < Lazers.Count do
begin
Lazer := TShape(Lazers[k]);
Lazer.Top := Lazer.Top - 10;
for m := 0 to Panels.Count-1 do
begin
Panel := TPanel(Panels[m]);
PanelHit := (Lazer.Top > (Panel.Top+Panel.Height)) and (Lazer.Left > Panel.Left) and (Lazer.Left < (Panel.Left+Panel.Width));
if PanelHit then
begin
Panels.Remove(Panel);
Panel.Free;
if Panels.Count = 0 then
PanelTimer.Enabled := False;
Break;
end;
end;
if PanelHit or (Lazer.Top = 0) then
begin
Lazers.Remove(Lazer);
Lazer.Free;
if Lazers.Count = 0 then
LazerTimer.Enabled := False;
end else
Inc(k);
end;
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
StartLazerAnimation;
end;
end.

Resources