Before I start I must state that no other stack overflow post on this topic had helped me yet
I have a dynamic button called by btnApply
It is created dynamically on a dynamic form frmSort by a on click event of static button btnSort on static form frmTable
Under the global scope var of frmTable is declared
btnApply: TButton;
Procedure btnApplyClick(Sender:TObject);
//other vars
Under the btnSort on click
//other code
btnApply:= TButton.create(frmSort);
//all its properties
BtnApply.onclick:= btnApplyClick;
//other code
Then later
Procedure btnApplyClick(Sender:TObject);
Begin
//it's code it has to execute
End;
I get an error message at the "BtnApply.onclick:= btnApplyClick;"
Line of incompatible types between method pointer and regular procedure
How do I make this work?
Thanks in advance
Your btnApplyClick needs to be a method of an object. Since the button has to be on a form to be useful anyway, make it a method of the form itself:
type
TfrmSort = class(TForm)
// UI controls listed here
public
procedure btnApplyClick(Sender: TObject);
end;
implementation
procedure TfrmSort.btnApplyClick(Sender: TObject);
begin
(Sender as TButton).Caption := 'You clicked me';
end;
procedure TfrmSort.FormCreate(Sender: TObject);
var
Btn: TButton;
begin
Btn := TButton.Create(Self);
Btn.Parent := Self;
Btn.Top := 100;
Btn.Left := 100;
Btn.OnClick := btnApplyClick;
end;
If for some reason you can't make it a form method (although I can't see how this would be the case for a visual control), you can make it a method of any object, like this:
implementation
// You must use StdCtrls in order to have the types available if
// it's not already in your uses clause
type
TDummyButtonClickObj = class
class procedure ButtonClickHandler(Sender: TObject);
end;
{ TDummyButtonClickObj }
class procedure TDummyButtonClickObj.ButtonClickHandler(Sender: TObject);
begin
(Sender as TButton).Caption := 'You clicked me.';
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
with TButton.Create(Self) do
begin
Parent := Self;
Top := 100;
Left := 100;
Caption := 'Click here';
OnClick := TDummyButtonClickObj.ButtonClickHandler;
end;
end;
As others have stated, the event handler should be a member of a class. That is what the event is expecting. However, it is also possible to use a non-member procedure as the event handler. It just takes a couple of extra steps to set up.
Add an extra explicit parameter to account for the Self pointer:
procedure btnApplyClick(Self: Pointer; Sender: TObject);
Use the TMethod record to assign the procedure to the button:
var
btnApply: TButton;
M: TMethod;
//other vars
Procedure btnApplyClick(Self: Pointer; Sender: TObject);
...
btnApply := TButton.create(frmSort);
//all its properties
M.Code := #btnApplyClick;
M.Data := nil; // can be anything you want passed to the Self parameter
BtnApply.onclick := TNotifyEvent(M);
//other code
...
procedure btnApplyClick(Self: Pointer; Sender: TObject);
Begin
// code to execute
End;
Related
I have created a login form which holds buttons corresponding to users' names held in an Access file. The buttons are created in the OnCreate event because I don't want to have to create them each time the screen is shown.
The buttons display as expected, and I have created LogOn and LogOff procedures, which both work as I expected.
The next step was to only display the buttons for users who are currently logged on to the system. To do this, I have created the following code in the OnActivate event:
procedure TUserInForm.FormActivate(Sender: TObject);
var
btn : TLBButton;
begin
With UserQuery do begin;
first;
while (not eof) do begin
BtnName := FieldByName('UserName').AsString;
Btn := TLBButton(FindComponent(BtnName));
if (Btn <> nil) then
if (FieldByName('LoggedIn').AsBoolean = True) then Btn.Visible := True else Btn.Visible := False;
next;
end;
end;
end;
However, it doesn't find any of the buttons - they are all nil. The code throws an Access Violation exception if I remove the nil check. But, at no point in the code do I destroy the buttons or the form itself. The buttons exist, because I can see them on the form. The BtnName variable is global within the unit. I've checked that the BtnName variable is populated correctly from the table.
I've used code similar to this to find components before, with no problems. In fact, I "stole" the code shown above from another procedure (with the obvious changes) in which it works fine. The logs show no errors.
Can anyone suggest some approach to fixing this problem? It's very frustrating!
FindComponent() searches the owned-components-list of the component that it is called on. I’m assuming your OnCreate handler creates the buttons with the Form as their Owner. But the with block will cause FindComponent() to be called on the UserQuery component instead of the Form. That would explain why the buttons are not being found.
So, you can either:
use Self.FindComponent() instead, since the OnActivate handler is being called on the Form, so Self will point at the Form:
procedure TUserInForm.FormActivate(Sender: TObject);
var
Btn : TLBButton;
BtnName : string;
begin
with UserQuery do begin
First;
while (not Eof) do begin
BtnName := FieldByName('UserName').AsString;
Btn := TLBButton(Self.FindComponent(BtnName));
if (Btn <> nil) then
Btn.Visible := FieldByName('LoggedIn').AsBoolean;
Next;
end;
end;
end;
get rid of the with block altogether, as it is generally considered to be bad practice to use with anyway in non-trivial cases (this situation is a good example of why):
procedure TUserInForm.FormActivate(Sender: TObject);
var
Btn : TLBButton;
BtnName : string;
begin
UserQuery.First;
while (not UserQuery.Eof) do begin
BtnName := UserQuery.FieldByName('UserName').AsString;
Btn := TLBButton(FindComponent(BtnName));
if (Btn <> nil) then
Btn.Visible := UserQuery.FieldByName('LoggedIn').AsBoolean;
UserQuery.Next;
end;
end;
if you want to keep using the with block, you can move the button search to a separate function that does not exist in the UserQuery component, so the with won’t be confused about which component to call the function on:
procedure TUserInForm.FormActivate(Sender: TObject);
var
Btn : TLBButton;
BtnName : string;
begin
with UserQuery do begin
First;
while (not Eof) do begin
BtnName := FieldByName('UserName').AsString;
Btn := FindButton(BtnName);
if (Btn <> nil) then
Btn.Visible := FieldByName('LoggedIn').AsBoolean;
Next;
end;
end;
end;
function TUserInForm.FindButton(const BtnName: string): TLBButton;
begin
Result := TLBButton(FindComponent(BtnName));
end;
Now, that being said, it would be a better design to add the created buttons to a list that you manage for yourself, rather than a list that the VCL manages on your behalf. Then you will always know exactly where to find the buttons. For example:
type
TUserInForm = class(TForm)
UserQuery: TQuery;
...
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
...
private
Buttons: TList;
function FindButton(const BtnName: string): TLBButton;
...
end;
...
procedure TUserInForm.FormCreate(Sender: TObject);
var
Btn : TLBButton;
begin
Buttons := TList.Create;
...
Btn := TLBButton.Create(Self);
Btn.Name := ...
Buttons.Add(Btn);
...
end;
procedure TUserInForm.FormDestroy(Sender: TObject);
begin
Buttons.Free;
end;
procedure TUserInForm.FormActivate(Sender: TObject);
var
Btn : TLBButton;
BtnName : string;
begin
UserQuery.First;
while (not UserQuery.Eof) do begin
BtnName := UserQuery.FieldByName('UserName').AsString;
Btn := FindButton(BtnName);
if (Btn <> nil) then begin
Btn.Visible := UserQuery.FieldByName('LoggedIn').AsBoolean;
end;
UserQuery.Next;
end;
end;
function TUserInForm.FindButton(const BtnName: string): TLBButton;
var
i: integer;
begin
for i := 0 to Buttons.Count-1 do begin
Result := TLBButton(Buttons[i]);
if Result.Name = BtnName then Exit;
end;
Result := nil;
end;
I'm doing a form manually, I have what I need but want to control the FormClose event, but can not find information on how to do it, I just want to create the event and FormClose code from the display.
What I have is:
function make_form():bool;
var
frm: TForm;
begin
frm := TForm.Create(nil);
frm.Caption := 'Title';
frm.Width := 500;
frm.Height := 300;
end;
This code is a function in a unit
How can I do this ?
Your functions is useless
Use try..finally when you creating an object.
Start with something like this
type
// Dummy class:
TFrmHandlers = class
// Close handlers:
class procedure FormClose(Sender: TObject; var Action: TCloseAction);
end;
implementation
.....
class procedure TFrmHandlers.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ShowMessage('The form will closed now');
end;
procedure make_form();
var
frm: TForm;
begin
frm := TForm.Create(nil);
try
frm.Caption := 'Title';
frm.Width := 500;
frm.Height := 300;
frm.OnClose := TFrmHandlers.FormClose;
frm.ShowModal;
finally
frm.Free;
end;
end;
You code is not real.
To treat Close event in dynamically created form, you have to assign event handler to event property OnClose:
frm.OnClose := CloseProc;
CloseProc should be a method of some object (for example, of main form) with needed prototype
TFormMain = class(TForm)
...
procedure CloseProc(Sender: TObject; var Action: TCloseAction);
...
implementation
procedure TformMain.CloseProc(Sender: TObject; var Action: TCloseAction);
begin
//use Sender if needed
end;
I have a form that has a list of useful procedures that I have created, that I often use in every project. I am adding a procedure that makes it simple to add a click-able image over where would be the TAccessory of a TListBoxItem. The procedure intakes the ListBox currently, but I would also need it to intake which procedure to call for the OnClick Event for the image.. Here is my existing code:
function ListBoxAddClick(ListBox:TListBox{assuming I need to add another parameter here!! but what????}):TListBox;
var
i : Integer;
Box : TListBox;
BoxItem : TListBoxItem;
Click : TImage;
begin
i := 0;
Box := ListBox;
while i <> Box.Items.Count do begin
BoxItem := Box.ListItems[0];
BoxItem.Selectable := False;
Click := Timage.Create(nil);
Click.Parent := BoxItem;
Click.Height := BoxItem.Height;
Click.Width := 50;
Click.Align := TAlignLayout.alRight;
Click.TouchTargetExpansion.Left := -5;
Click.TouchTargetExpansion.Bottom := -5;
Click.TouchTargetExpansion.Right := -5;
Click.TouchTargetExpansion.Top := -5;
Click.OnClick := // this is where I need help
i := +1;
end;
Result := Box;
end;
The desired procedure would be defined in the form that is calling this function.
Since the OnClick event is of type TNotifyEvent you should define a parameter of that type. Look at this (I hope self-explaining) example:
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
private
procedure TheClickEvent(Sender: TObject);
end;
implementation
procedure ListBoxAddClick(ListBox: TListBox; OnClickMethod: TNotifyEvent);
var
Image: TImage;
begin
Image := TImage.Create(nil);
// here is assigned the passed event method to the OnClick event
Image.OnClick := OnClickMethod;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
// here the TheClickEvent event method is passed
ListBoxAddClick(ListBox1, TheClickEvent);
end;
procedure TForm1.TheClickEvent(Sender: TObject);
begin
// do something here
end;
There are TPopupMenu and three buttons on the form named "AddButton", "EditButton", and "DestroyButton" and added OnClick events to all three buttons. The TPopupMenu in the PopupMenu property of the form. I have created the PopupMenuItemsClick procedure in the TForm1 type declaration so that it can be used as the method call for the menu item OnClick event.
type
TForm1 = class(TForm)
AddButton: TButton;
EditButton: TButton;
DestroyButton: TButton;
PopupMenu1: TPopupMenu;
procedure AddButtonClick(Sender: TObject);
procedure EditButtonClick(Sender: TObject);
procedure DestroyButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
procedure PopupMenuItemsClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.AddButtonClick(Sender: TObject);
var
index: Integer;
NewItem: TMenuItem;
begin
// The owner (PopupMenu1) will clean up this menu item.
NewItem := TMenuItem.Create(PopupMenu1); // Create the new item.
index := PopupMenu1.Items.Count;
PopupMenu1.Items.Add(NewItem);// Add it to the pop-up menu.
NewItem.Caption := 'Menu Item ' + IntToStr(index);
NewItem.Tag := index;
NewItem.OnClick :=
PopupMenuItemsClick; // Assign it an event handler.
end;
procedure TForm1.PopupMenuItemsClick(Sender: TObject);
begin
with Sender as TMenuItem do
begin
case Tag of
0: ShowMessage('first item clicked');
1: ShowMessage('second item clicked');
2: ShowMessage('third item clicked');
3: ShowMessage('fourth item clicked');
end;
end;
end;
{
To edit or destroy an item, grab its pointer
using the Items property.
procedure TForm1.EditButtonClick(Sender: TObject);
var
ItemToEdit: TMenuItem;
begin
ItemToEdit := PopupMenu.Items[1];
ItemToEdit.Caption := 'Changed Caption';
end;
procedure TForm1.DestroyButtonClick(Sender: TObject);
var
ItemToDelete: TMenuItem;
begin
ItemToDelete := PopupMenu.Items[2];
ItemToDelete.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
index: Integer;
NewItem: TMenuItem;
begin
for index := 0 to 3 do
begin
// The owner (PopupMenu1) will clean up this menu item.
NewItem := TMenuItem.Create(PopupMenu1); // Create the new item.
PopupMenu1.Items.Add(NewItem);// Add it to the pop-up menu.
NewItem.Caption := 'Menu Item ' + IntToStr(index);
NewItem.Tag := index;
NewItem.OnClick :=
PopupMenuItemsClick; // Assign it an event handler.
end;
end;
But PopupMenu is not appearing when I clicked on addmenu button. Anyone can find what is the reason why Popupmenu is not appearing when form is loaded or any button clicked.
your code not what you really need
use this code and it will work perfectly
procedure TForm1.PopupMenuItemsClick(Sender: TObject);
var ICount : Integer;
begin
ICount := TMenuItem(Sender).MenuIndex;
ShowMessage('Item Number '+ IntToStr(ICount+1) + ' Selected');
end;
procedure TForm1.AddClick(Sender: TObject);
var
Index: Integer;
NewItem: TMenuItem;
begin
NewItem := TMenuItem.Create(PopupMenu);
Index := PopupMenu.Items.Count;
PopupMenu.Items.Add(NewItem);
NewItem.Caption := 'Menu Item ' + IntToStr(Index);
NewItem.Tag := Index;
NewItem.OnClick := PopupMenuItemsClick;
PopupMenu.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
end;
I tested it with Delphi7, XE2 and XE3 its working
Add this line in the FormCreate or set this property in Object Inspector.
self.PopupMenu:=PopupMenu1;
This comments may help to solve the problem (i was having similar in old Delphi versions, i do not have XE to test on).
Never, ever create a component and let empty its .Name, allways
assign it a unique value (i see a lot of faulty interna code when let empty, since they can not be empty).
And allways assign properties and events to the componet prior to add
them onto their parent.
See this suggestions in the comments:
procedure TForm1.AddClick(Sender: TObject);
var
Index: Integer;
NewItem: TMenuItem;
begin
NewItem := TMenuItem.Create(PopupMenu);
Index := PopupMenu.Items.Count;
//PopupMenu.Items.Add(NewItem); // Not the correct place, see below
NewItem.Name : = 'SomeText' + IntToStr(Index); // Name them, with a unique name not starting with a number (also there is no need to put a number)
NewItem.Caption := 'Menu Item ' + IntToStr(Index);
NewItem.Tag := Index;
NewItem.OnClick := PopupMenuItemsClick;
PopupMenu.Items.Add(NewItem); // After properties has been set, never before
PopupMenu.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);
// Do not forget to free such menu item somewhere on your code, obviously not here
end;
And with menus, remember to free the items created, they do not free by them selfs and names will be in use next time.
How can I create a component at runtime and then work with it (changing properties, etc.)?
It depends if it is a visual or non-visual component. The principle is the same, but there are some additional considerations for each kind of component.
For non-visual components
var
C: TMyComponent;
begin
C := TMyComponent.Create(nil);
try
C.MyProperty := MyValue;
//...
finally
C.Free;
end;
end;
For visual components:
In essence visual components are created in the the same way as non-visual components. But you have to set some additional properties to make them visible.
var
C: TMyVisualComponent;
begin
C := TMyVisualComponent.Create(Self);
C.Left := 100;
C.Top := 100;
C.Width := 400;
C.Height := 300;
C.Visible := True;
C.Parent := Self; //Any container: form, panel, ...
C.MyProperty := MyValue,
//...
end;
A few explanations to the code above:
By setting the owner of the component (the parameter of the constructor) the component gets destroyed when the owning form gets destroyed.
Setting the Parent property makes the component visible. If you forget it your component will not be displayed. (It's easy to miss that one :) )
If you want many components you can do the same as above but in a loop:
var
B: TButton;
i: Integer;
begin
for i := 0 to 9 do
begin
B := TButton.Create(Self);
B.Caption := Format('Button %d', [i]);
B.Parent := Self;
B.Height := 23;
B.Width := 100;
B.Left := 10;
B.Top := 10 + i * 25;
end;
end;
This will add 10 buttons at the left border of the form. If you want to modify the buttons later, you can store them in a list. (TComponentList ist best suited, but also take a look at the proposals from the comments to this answer)
How to assign event handlers:
You have to create an event handler method and assign it to the event property.
procedure TForm1.MyButtonClick(Sender: TObject);
var
Button: TButton;
begin
Button := Sender as TButton;
ShowMessage(Button.Caption + ' clicked');
end;
B := TButton.Create;
//...
B.OnClick := MyButtonClick;
To simplify the runtime component creation process, you can use GExperts.
Create a component (or more components) visually and set its properties.
Select one or more components and execute GExperts, Components to Code.
Paste the generated code into your application.
Remove component(s) from the visual form designer.
Example (TButton-creation code generated in this way):
var
btnTest: TButton;
btnTest := TButton.Create(Self);
with btnTest do
begin
Name := 'btnTest';
Parent := Self;
Left := 272;
Top := 120;
Width := 161;
Height := 41;
Caption := 'Component creation test';
Default := True;
ParentFont := False;
TabOrder := 0;
end;
I would just like to add that when dynamically adding controls...
it as a good idea to add them to an object list (TObjectList) as suggested in <1> by #Despatcher.
procedure Tform1.AnyButtonClick(Sender: TObject);
begin
If Sender is TButton then
begin
Case Tbutton(Sender).Tag of
.
.
.
// Or You can use the index in the list or some other property
// you have to decide what to do
// Or similar :)
end;
end;
procedure TForm1.BtnAddComponent(Sender: TObJect)
var
AButton: TButton;
begin
AButton := TButton.Create(self);
Abutton. Parent := [Self], [Panel1] [AnOther Visual Control];
AButton.OnClick := AnyButtonClick;
// Set Height and width and caption ect.
.
.
.
AButton.Tag := MyList.Add(AButton);
end;
You need to add the Unit 'Contnrs' to your Uses list.
I.e System.Contnrs.pas the base Containers Unit
And you can have many object lists.
I suggest using a TObjectList for each type of control that you use
e.g.
Interface
Uses Contnrs;
Type
TMyForm = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
Var
MyForm: TMyForm;
checkBoxCntrlsList: TObjectList; //a list for the checkBoxes I will createin a TPanel
comboboxCntrlsList: TObjectList; //a list of comboBoxes that I will create in some Form Container
this allows you to easily manipulate/manage each control as you will know what type of control it is e.g.
Var comboBox: TComboBox;
I: Integer;
begin
For I = 0 to comboboxCntrlsList.Count -1 do // or however you like to identify the control you are accessing such as using the tag property as #Despatcher said
Begin
comboBox := comboboxCntrlsList.Items[I] as TComboBox;
...... your code here
End;
end;
This allows you to then use the methods and properties of that control
Don't forget to create the TObjectLists, perhaps in the form create event...
checkBoxCntrlsList := TObjectList.Create;
comboboxCntrlsList := TObjectList.Create;
But if I don't surely know how many components I want to create, e.g. if it depends on user's decision. So how can I declare components dynamically?
The answer has been suggested - the easiest way is a List of Objects(components). TObjectList is the simplest to use (in unit contnrs). Lists are great!
In Form1 Public
MyList: TObjectList;
procedure AnyButtonClick(Sender: TObject);
// You can get more sophisticated and declare //TNotifyevents and assign them but lets keep it simple :)
.
.
.
procedure Tform1.AnyButtonClick(Sender: TObject);
begin
If Sender is TButton then
begin
Case Tbutton(Sender).Tag of
.
.
.
// Or You can use the index in the list or some other property
// you have to decide what to do
// Or similar :)
end;
end;
procedure TForm1.BtnAddComponent(Sender: TObJect)
var
AButton: TButton;
begin
AButton := TButton.Create(self);
Abutton. Parent := [Self], [Panel1] [AnOther Visual Control];
AButton.OnClick := AnyButtonClick;
// Set Height and width and caption ect.
.
.
.
AButton.Tag := MyList.Add(AButton);
end;
An Object list can contain any object visual or not but that gives you an added overhead of sorting out which items are which - better to have related lists if you want multiple dynamic controls on similar panels for instance.
Note: like other commenters I may have over-simplified for brevity but I hope you ge the idea. You need a mechanism to manage the objects once they are created and lists are excellent for this stuff.
Some components override the 'Loaded' method. This method will not be called automatically if you create an instance at runtime. It will be called by Delphi when loading from the form file (DFM) is complete.
If the method contains initialization code, your application might show unexpected behaviour when created at runtime. In this case, check if the component writer has used this method.
If you nest win controls in Group Boxes/Page Controls/Etc..., I think it is beneficial to have the parent group box also be the owner. I've noticed a sharp decrease in window close times when doing this, as opposed to having the owner always be the main form.
During a research on "creating a delphi form using xml based template", I find something useful pointing out RTTI and using open tools api (ToolsApi.pas I think). Have a look at the interfaces in the unit.
Very ease. Call Create. Example:
procedure test
var
b : TButton;
begin
b:=TButton.Create(nil);
b.visible:=false;
end;
This creates a component (TButton is a component) at runtime and sets the property visible.
For the constructor: pass nil if you want to manage the memory yourself. Pass a pointer another component if you want to have it destroyed when the other component is destroyed.
This is example how to emulate button tag on Evernote
unit Unit7;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, CHButton, Vcl.ExtCtrls, RzPanel, CHPanel, RzCommon,RzBmpBtn, Vcl.StdCtrls;
type
// This is panel Button
TButtonClose = class (TRzPanel)
CloseButton : TRzBmpButton;
procedure CloseButtonClick(Sender: TObject);
procedure CloseButtonMouseEnter(Sender: TObject);
procedure MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
TForm7 = class(TForm)
CHButton1: TCHButton;
RzPanel1: TRzPanel;
RzBmpButton1: TRzBmpButton;
procedure CHButton1Click(Sender: TObject);
procedure RzBmpButton1Click(Sender: TObject);
procedure RzPanel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure RzPanel1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure RzPanel1MouseEnter(Sender: TObject);
procedure RzBmpButton1MouseEnter(Sender: TObject);
procedure FormMouseEnter(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form7: TForm7;
MyCloseButton : TButtonClose;
implementation
{$R *.dfm}
// constructor for on the fly component created
constructor TButtonClose.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
// Set Events for the component
Self.OnMouseEnter := Self.CloseButtonMouseEnter;
Self.OnMouseDown := Self.MouseDown;
Self.OnMouseUp := Self.MouseUp;
Self.Height := 25;
// Close button on top panel Button
// Inherited from Raize Bitmap Button
CloseButton := TRzBmpButton.Create(self);
// Set On Click Event for Close Button
CloseButton.OnClick := Self.CloseButtonClick;
// Place Close Button on Panel Button
CloseButton.Parent := self;
CloseButton.Left := 10;
CloseButton.Top := 5;
CloseButton.Visible := False;
// Setting the image for the button
CloseButton.Bitmaps.Up.LoadFromFile(ExtractFilePath(Application.ExeName)+'\close.bmp');
end;
procedure TButtonClose.CloseButtonClick(Sender: TObject);
begin
// Free the parent (Panel Button)
TControl(Sender).Parent.Free;
end;
procedure TButtonClose.CloseButtonMouseEnter(Sender: TObject);
begin
// Show the Close button
CloseButton.Visible := True;
end;
procedure TButtonClose.MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
// Emulate Button down state, since it is panel
TRzPanel(Sender).BorderOuter := fsLowered;
end;
procedure TButtonClose.MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
// Emulate Button up state, since it is panel
TRzPanel(Sender).BorderOuter := fsRaised;
end;
destructor TButtonClose.Destroy;
begin
inherited Destroy;
end;
procedure TForm7.FormCreate(Sender: TObject);
begin
// Create Panel Button on the fly
MyCloseButton := TButtonClose.Create(self);
MyCloseButton.Caption := 'My Button';
MyCloseButton.Left := 10;
MyCloseButton.Top := 10;
// Don't forget to place component on the form
MyCloseButton.Parent := self;
end;
procedure TForm7.FormMouseEnter(Sender: TObject);
begin
if Assigned(RzBmpButton1) then
RzBmpButton1.Visible := False;
// Hide when mouse leave the button
// Check first if myCloseButton Assigned or not before set visible property
if Assigned(MyCloseButton.CloseButton) then
MyCloseButton.CloseButton.Visible := False;
end;
procedure TForm7.RzBmpButton1Click(Sender: TObject);
begin
TControl(Sender).Parent.Free;
end;
procedure TForm7.RzBmpButton1MouseEnter(Sender: TObject);
begin
RzBmpButton1.Visible := True;
end;
procedure TForm7.RzPanel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
TRzPanel(Sender).BorderOuter := fsLowered;
end;
procedure TForm7.RzPanel1MouseEnter(Sender: TObject);
begin
RzBmpButton1.Visible := True;
end;
procedure TForm7.RzPanel1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
TRzPanel(Sender).BorderOuter := fsRaised;
end;
procedure TForm7.CHButton1Click(Sender: TObject);
begin
FreeAndNil(Sender);
end;
end.