TComboEdit component - delphi

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;

Related

TPopupMenu as subcomponent, don't works

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

Modal dialog does not return focus to application

I have a custom control derived from TPanel named TTestCtrl. It holds a TImage32 (from Graphics32).
When the user double clicks on the image, I show a message. The problem is that after I close the message, the focus is not returned back to the main application. So, the first click, no matter what I click on in the main app/main form, is lost.
Strange thing: If I call the Mesaj() procedure not from the TTestCtrl but from the main form, it works (the first click is not lost anymore):
unit DerivedControl;
interface
uses
System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.Dialogs, Vcl.Forms, GR32, GR32_Image;
type
TTestCtrl = class(TPanel)
private
Img: TImage32;
protected
procedure ChromaDblClick(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
published
end;
procedure Mesaj(const MessageText, Title: string);
implementation
procedure Mesaj(const MessageText, Title: string);
begin
{$IFDEF MSWINDOWS}
Application.MessageBox(PChar(MessageText), PChar(Title), 0) { 'Title' will appear in window's caption }
{$ELSE}
MessageDlg(MessageText, mtInformation, [mbOk], 0);
{$ENDIF}
end;
constructor TTestCtrl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 200;
Height := 86;
Img := TImage32.Create(Self);
Img.Parent := Self;
Img.Align := alClient;
Img.OnDblClick := ChromaDblClick;
end;
procedure TTestCtrl.ChromaDblClick(Sender: TObject);
begin
Mesaj('Caption', 'From derived control'); // focus lost
end;
end.
The simple/minimal application below is the tester:
unit TesterForm;
interface
uses
System.SysUtils, System.Classes, Vcl.StdCtrls, Vcl.Samples.Spin, Vcl.Controls, vcl.Forms, DerivedControl;
type
TfrmTester = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
public
end;
var
frmTester: TfrmTester;
implementation
{$R *.dfm}
var
Ctrl: TTestCtrl;
procedure TfrmTester.FormCreate(Sender: TObject);
begin
Ctrl := TTestCtrl.Create(Self);
Ctrl.Parent := Self;
end;
procedure TfrmTester.Button1Click(Sender: TObject);
begin
Mesaj('Caption', 'From main form'); // works
end;
end.
Try this :
procedure TTestCtrl.ChromaDblClick(Sender: TObject);
var F : TcustomForm;
begin
Mesaj('Caption', 'From derived control'); // focus lost
F := GetParentForm(Self);
if Assigned(F) then F.BringToFront;
end;

creating composite controls in firemonkey

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.

How to create Delphi component inherited from few other components?

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;

On Mouse Enter TShape

I have a TMachine class, that is a TShape class
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 }
public
{ Public declarations }
procedure PlaceShape(sizeW,sizeH :integer; name, order,asset : string);
end;
implementation
Procedure TMachine.PlaceShape(sizeW,sizeH :integer; name, order,asset : string);
begin
self.width := sizeW;
self.height := sizeH;
self.top := 136;
self.left := MyDataModule.fDB.LastX +2;//set left
MyDataModule.fDB.lastx := left + sizeW;
end;
end.
How would i add onmouseenter code for this? So when the shape is added during run time it will have its own on mouse enter code. Something like this, I know this wont work.. but maybe it will show you what i am looking to do? So when i create a TMachine, i would pass the name and number to this procedure and it would make the onmouseenter procedure update with the name/number i sent it.
Procedure TMachine.EditMouseEnter(name,number :string);
begin
....onmouseenter(Label2.Caption := name AND label3.caption := Number)...
end
Add an OnMouseEnter event:
type
TMachineEvent = procedure(Sender: TMachine) of object;
TMachine = class(TShape)
private
FOnMouseEnter: TMachineEvent;
...
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
protected
procedure DoMouseEnter; virtual;
published
property OnMouseEnter: TMachineEvent read FOnMouseEnter write FOnMouseEnter;
...
end;
implementation
{ TMachine }
procedure TMachine.CMMouseenter(var Message: TMessage);
begin
DoMouseEnter;
inherited;
end;
procedure TMachine.DoMouseEnter;
begin
if Assigned(FOnMouseEnter) then
FOnMouseEnter(Self);
end;
And assign that event at runtime:
procedure TForm1.CreateMachine;
var
Machine: TMachine;
begin
Machine := TMachine.Create(Self);
Machine.SetBounds(...);
Machine.OnMouseEnter := MachineMouseEnter;
Machine.Parent := Self;
end;
procedure TForm1.MachineMouseEnter(Sender: TMachine);
begin
Label2.Caption := Sender.Name;
Label3.Caption := Sender.Number;
end;

Resources