Delphi XE-6
I am trying to create my own custom Firemonkey control derived from TGroupBox, where I create a TGridPanelLayout Control on the groupbox.
constructor TMyRadioGroup.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FLayout:= TGridPanelLayout.Create(self);
FLayout.Parent:= self;
end;
How do I prevent the user from being able to select and /or delete the TGridPanelLayout control? At design time, I only want my parent control (derived from TGroupbox) to be select-able and delete-able from the form.
You need to set the Stored property to false for each child control you do not want selectable at design time. For example the following code creates a panel with two child controls, a TEdit and a TButton.
unit PanelCombo;
interface
uses
System.SysUtils, System.Classes, FMX.Types, FMX.Controls,
FMX.Controls.Presentation, FMX.StdCtrls, FMX.Edit;
type
TPanelCombo = class(TPanel)
private
{ Private declarations }
edit1: TEdit;
button1: TButton;
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TPanelCombo]);
end;
constructor TPanelCombo.Create(AOwner: TComponent);
begin
inherited;
edit1:= TEdit.create(self);
edit1.parent:= self;
edit1.align:= TAlignLayout.Top;
edit1.stored:= false;
button1:= TButton.create(self);
button1.parent:= self;
button1.align:= TAlignLayout.bottom;
button1.stored:= false;
end;
destructor TPanelCombo.Destroy;
begin
inherited;
edit1.Free;
button1.Free;
end;
end.
Related
I'm trying to build a component based on FMX.Objects.TImage. I want the permanently assigned images by MultiResBitmap.Items to change without having to use OnMouseEnter and OnMouseLeave in the application. Of course, I will use the constructor and the destructor.
I'm a beginner, and maybe I don't understand something. I've been trying for a week now, and I can't detect the mouse over the component and assign events correctly to it. I temporarily used ShowMessage() for the test.
Theoretically, this code should probably work and not work. Tell me what I'm doing wrong.
unit ImageCustoms;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, FMX.Types, vcl.Controls, FMX.Objects, FMX.ImgList, vcl.Dialogs, vcl.Graphics, FMX.ExtCtrls;
type
TImageCostoms = class(TImage)
private
{ Private declarations }
FOnMouseLeave: TNotifyEvent;
FOnMouseEnter: TNotifyEvent;
procedure CMMouseEnter(var msg: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var msg: TMessage); message CM_MOUSELEAVE;
protected
{ Protected declarations }
procedure DoMouseEnter; virtual;
procedure DoMouseLeave; virtual;
public
{ Public declarations }
//constructor Create(AOwner: TComponent); override;
//destructor Destroy; override;
published
{ Published declarations }
property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TImageCostoms]);
end;
procedure TImageCostoms.CMMouseEnter(var msg: TMessage);
begin
ShowMessage('Enter');
DoMouseEnter;
end;
procedure TImageCostoms.CMMouseLeave(var msg: TMessage);
begin
ShowMessage('Leave');
DoMouseLeave;
end;
procedure TImageCostoms.DoMouseEnter;
begin
if Assigned(FOnMouseEnter) then
ShowMessage('Enter');
FOnMouseEnter(Self);
end;
procedure TImageCostoms.DoMouseLeave;
begin
if Assigned(FOnMouseLeave) then
ShowMessage('Leave');
FOnMouseLeave(Self);
end;
{constructor TImageCostoms.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png'); // .\img\i.png
end;
destructor TImageCostoms.Destroy;
begin
inherited Destroy;
end; }
end.
First off, don't mix VCL and FMX units together in your own units. VCL and FMX are not designed to be used together. And since FMX is cross-platform, don't use Winapi units in your code unless you are writing Windows-specific code (which you are not, in this situation).
You don't need to handle the CM_MOUSE(ENTER|LEAVE) messages directly, the framework already does that internally for you. And you don't need to redeclare the OnMouse(Enter|Leave) events, they already exist and are published in TImage.
All you really need to do is override (not redeclare) the existing virtual DoMouse(Enter|Leave) methods from Timage, eg:
unit ImageCustoms;
interface
uses
System.SysUtils, System.Classes, FMX.Types, FMX.Objects, FMX.ImgList, FMX.ExtCtrls;
type
TImageCostoms = class(TImage)
private
{ Private declarations }
protected
{ Protected declarations }
procedure DoMouseEnter; override;
procedure DoMouseLeave; override;
public
{ Public declarations }
//constructor Create(AOwner: TComponent); override;
//destructor Destroy; override;
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TImageCostoms]);
end;
procedure TImageCostoms.DoMouseEnter;
begin
...
inherited;
end;
procedure TImageCostoms.DoMouseLeave;
begin
...
inherited;
end;
{constructor TImageCostoms.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png'); // .\img\i.png
end;
destructor TImageCostoms.Destroy;
begin
inherited Destroy;
end; }
end.
Don't use ShowMessage() to debug component code, especially in events that react to keyboard/mouse focus changes. If you want to see debug messages, use OutputDebugString() or equivilent instead, and then look for the messages in the IDE's Output window. Or, just make display changes in your UI, like color changes, etc.
Thank you, it helped me, I was trying very uphill. In fact, in FMX it is simple and everything works. Thank you very much. I write the virtual keyboard support for the program, the whole is just a transparent button changing the focus slightly. Thanks again. For posterity, for now, it looks like this, I will try to add support from the global ImageList.
interface
uses
System.SysUtils, System.Classes, FMX.Types, FMX.Objects, FMX.ImgList, vcl.Dialogs, System.UITypes;
type
TImageCostoms = class(TImage)
private
{ Private declarations }
procedure DoMouseEnter; override;
procedure DoMouseLeave; override;
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TImageCostoms]);
end;
procedure TImageCostoms.DoMouseEnter;
begin
inherited ;
MultiResBitmap.Items[1].Bitmap.LoadFromFile('focus1.png');
end;
procedure TImageCostoms.DoMouseLeave;
begin
inherited;
MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png');
end;
constructor TImageCostoms.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
width:=45;
height:=45;
MultiResBitmap.Items[0].Bitmap.LoadFromFile('focus0.png');
end;
end.```
I'm trying to develop a component, specifically a button linked to a popup menu.
I can not understand why I do not see the PopupMenu.
Down here my code:
unit DropDownButton;
interface
uses
System.SysUtils,
System.Classes,
Vcl.Controls,
Vcl.StdCtrls,
System.Types,
Vcl.Menus;
type
TDropDownButton = class;
TDropDownButton = class(TButton)
private
FDropDownMenu: TPopupMenu;
protected
public
constructor Create(AOwner: TComponent); override;
procedure Click; override;
published
property DropDownMenu: TPopupMenu read FDropDownMenu;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Flexline', [TDropDownButton]);
end;
constructor TDropDownButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FDropDownMenu:= TPopupMenu.Create(Self);
FDropDownMenu.Name:= 'Menu';
FDropDownMenu.SetSubComponent(True);
end;
procedure TDropDownButton.Click;
var
_point: TPoint;
begin
_point:= Self.ClientToScreen(Point(0,0));
FDropDownMenu.Popup(_point.X,_point.Y + Height);
inherited Click;
end;
end.
Thanks in advance.
I'd like to make a dropdown button to use in my project
I would like to create a Delphi component which can have the style of TComboBox or TEdit. If I set the style as stCombo I would like to see a TComboBox and if I set to stEdit then I would like to see the component as a TEdit.
The main reason of this component will be to change the look of TComboBox when is ReadOnly to an colored TEdit.
Also, when is styled as stEdit, I would like to add some features to TEdit.
I've tried to descend the component from TCustomPanel, TCustomComboBox or even TWinControl.
unit ComboEdit;
interface
uses
Winapi.Windows, Winapi.Messages,
System.Classes, System.SysUtils, System.Types, System.DateUtils,
Vcl.StdCtrls, VCL.ExtCtrls, Vcl.Controls, Vcl.Graphics, Vcl.Dialogs,
Vcl.Forms, Vcl.Buttons, Vcl.Themes, Vcl.ComCtrls;
type
TStyle = (stCombo, stEdit);
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
TComboEdit = class(TWinControl)
private
FPanel: TPanel;
FCombo: TComboBox;
FEdit: TEdit;
FStyle: TStyle;
procedure SetStyle(const Value: TStyle);
protected
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Style: TStyle read FStyle write SetStyle;
end;
implementation
constructor TComboEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width:= 145;
Height:= 21;
FPanel:= TPanel.Create(AOwner);
FPanel.Parent:= Self;
FPanel.Top:= 0;
FPanel.Left:= 0;
FPanel.Width:= 145;
FPanel.Height:= 21;
FCombo:= TComboBox.Create(AOwner);
FCombo.Parent:= FPanel;
FCombo.Top:= 0;
FCombo.Left:= 0;
FCombo.Width:= 145;
FCombo.Height:= 21;
FEdit:= TEdit.Create(AOwner);
FEdit.Parent:= FPanel;
FEdit.Top:= 0;
FEdit.Left:= 0;
FEdit.Width:= 145;
FEdit.Height:= 21;
FEdit.Visible:= False;
FStyle:= stCombo;
end;
destructor TComboEdit.Destroy;
begin
FreeAndNil(FPanel);
FreeAndNil(FCombo);
FreeAndNil(FEdit);
inherited Destroy;
end;
procedure TComboEdit.SetStyle;
begin
if Value <> FStyle then
begin
FStyle:= Value;
case FStyle of
stCombo:
begin
FCombo.Visible:= True;
FEdit.Visible:= False;
end;
stEdit:
begin
FCombo.Visible:= False;
FEdit.Visible:= True;
end;
end;
Invalidate;
end;
end;
end.
If I do like this I get some nasty errors and I don't like the fact that editors can be selected inside of Panel.
PS: I'm aware about csSimple style from TComboBox but it looks different than TEdit (see below)
I succeed to do it by creating compound component as indicated on this link
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
TComboEdit = class(TWinControl)
private
FCombo: TComboBox;
FEdit: TEdit;
FReadOnly: Boolean;
FStyle: TStyle;
procedure SetReadOnly(const Value: Boolean);
procedure SetStyle(const Value: TStyle);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Combo: TComboBox read FCombo;
property Edit: TEdit read FEdit;
property ReadOnly: Boolean read FReadOnly write SetReadOnly default False;
property Style: TStyle read FStyle write SetStyle default stCombo;
property Align;
property Font;
property ParentFont;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
end;
constructor TComboEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FReadOnly:= False;
FStyle:= stCombo;
Width:= 145;
Height:= 21;
FCombo:= TComboBox.Create(Self);
FCombo.Parent:= Self;
FCombo.Align:= alClient;
FCombo.Name:= 'ComboBox';
FCombo.SetSubComponent(True); //<--- here is the trick
FEdit:= TEdit.Create(Self);
FEdit.Parent:= Self;
FEdit.Visible:= False;
FEdit.Align:= alClient;
FEdit.Name:= 'Edit';
FEdit.SetSubComponent(True); //<--- here is the trick
end;
Being new to OOP, I'm curious why Delphi XE7 generated an invalid pointer operation on a logging class I was using whenI try to free it. So I created a simple test to create an object and then free it. I'm not sure what I'm missing here and why it throws this exception when MyObject.Free is called.
In the first unit, I create an instance of this object as shown here.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Unit2;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
MyObject: TMyObject;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
MyObject := TMyObject.Create;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
MyObject.Free;
end;
end.
In the 2nd unit, I have the object defined as follows.
unit Unit2;
interface
uses System.Classes;
type
TMyObject = class
public
constructor Create;
destructor Free;
end;
implementation
constructor TMyObject.Create;
begin
inherited Create;
end;
destructor TMyObject.Free;
begin
inherited Free;
end;
end.
Any help is appreciated.
Always implement a destructor by overriding the virtual destructor named Destroy.
type
TMyObject = class
public
constructor Create;
destructor Destroy; override;
end;
constructor TMyObject.Create;
begin
inherited;
end;
destructor TMyObject.Destroy;
begin
inherited;
end;
To destroy an instance call the method named Free in TObject. This calls the virtual destructor Destroy only if the instance is not nil.
Learn more from the documentation:
http://docwiki.embarcadero.com/Libraries/en/System.TObject.Free
http://docwiki.embarcadero.com/Libraries/en/System.TObject.Destroy
The name MyObject is weak. Object is used for instances. Class is used for classes.
Tutorials that I found about how to create delphi components were nice, but they only used one of existing components as object to inherit actions from. Something like this
unit CountBtn;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TCountBtn = class(TButton)
private
FCount: integer;
protected
procedure Click;override;
public
procedure ShowCount;
published
property Count:integer read FCount write FCount;
constructor Create(aowner:Tcomponent); override;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Mihan Components', [TCountBtn]);
end;
constructor TCountBtn.Create(aowner:Tcomponent);
begin
inherited create(Aowner);
end;
procedure Tcountbtn.Click;
begin
inherited click;
FCount:=FCount+1;
end;
procedure TCountBtn.ShowCount;
begin
Showmessage('On button '+ caption+' you clicked: '+inttostr(FCount)+' times');
end;
end.
But what should I do if I need component which use few elements? Lets say, I got Button and Edit field. And on button click there in edit field should appers text the same as on button. I start to make it like this, but seems like it's not gonna work as I want:
unit TestComp;
interface
uses
System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TUiCompU = class(TCustomControl)
private
{ Private declarations }
FButton: TButton;
FEdit: TEdit;
protected
{ Protected declarations }
procedure Paint; override;
//wrong!
procedure FButton.Click;override
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
published
{ Published declarations }
//wrong!
property ButtonText: String read FButton.Caption write FButton.Caption;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Ui', [TUiCompU]);
end;
{ TUiCompU }
constructor TUiCompU.Create(AOwner: TComponent);
begin
inherited;
Width := 200;
Height := 50;
FButton := TButton.Create(Self);
FButton.SetSubComponent(True);
FButton.Parent := Self;
FButton.Top := 8;
FButton.Left := 50;
FButton.Width := 35;
FButton.Name := 'Button';
FEdit := TEdit.Create(Self);
FEdit.SetSubComponent(True);
FEdit.Parent := Self;
FEdit.Top := 8;
FEdit.Left := 84;
FEdit.Width := 121;
FEdit.Name := 'Edit';
end;
procedure TUiCompU.Paint;
begin
Canvas.Rectangle(ClientRect);
end;
end.
How should I add here Click procedure, which is realte to click on the button? And is there are good tutorial about how to made good components using others? (I need to create something like slideshow component btw).
Thank you, and sorry for my english.
You can write methods for the subcomponent events, but it has one big weakness; if you publish those subcomponents, there is a risk that someone will steal you this binding by writing own method:
type
TUiCompU = class(TCustomControl)
private
FEdit: TEdit;
FButton: TButton;
procedure ButtonClick(Sender: TObject);
procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
public
constructor Create(AOwner: TComponent); override;
end;
implementation
constructor TUiCompU.Create(AOwner: TComponent);
begin
inherited;
FButton := TButton.Create(Self);
...
FButton.OnClick := ButtonClick;
FEdit := TEdit.Create(Self);
...
FEdit.OnKeyDown := EditKeyDown;
end;
procedure TUiCompU.ButtonClick(Sender: TObject);
begin
// do whatever you want here
end;
procedure TUiCompU.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
// do whatever you want here
end;