I want to override the OnPaint-Event of the TBCDProgressBar Component. It's a component for Lazarus (freepascal), I tagged Delphi on purpose because there are no differences when overriding events, and I want as much help as I can get.
TBCDProgressBar has no OnPaint event in its decleration:
TBCDProgressBar = class(TCDProgressBar)
private
FBCThemeManager: TBCThemeManager;
procedure SetFBCThemeManager(AValue: TBCThemeManager);
public
constructor Create(AOwner: TComponent); override;
published
property ThemeManager: TBCThemeManager read FBCThemeManager write SetFBCThemeManager;
end;
My first approach was to trace down TBCDProgressBar until I would find the OnPaint-Event.
Result was:
TCDProgressBar = class(TCDControl)
TCDControl = class(TCustomControl)
TCustomControl = class(TWinControl)
And finally in TCustomControl I found property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
I don't understand how I can override OnPaint from TCustomControl so that it affects the TBCDProgressBar.
Edit://
I didn't know you can override it as usual, so here is the solution for anyone having the same problem:
TBCDProgressBarWithOnPaint = class(TBCDProgressBar)
protected
procedure Paint; override;
end;
procedure TBCDProgressBarWithOnPaint.Paint;
begin
inherited;
// drawing a line on Progressbar
Canvas.Pen.Color:=clRed;
Canvas.Line(200,0,200,20);
end;
If it is visible (protected, public or published) and virtual, then you can override it no matter how far up the tree it is, just as if it were declared in TProgressBar.
Related
I create a component and add a Tbutton to it.
now I want to create OnClick event for my Component that execute when user click my component's Button at run time
How can I do that?
#LU_RD's answer is probably what you are looking for.
I wrote a smaller example that should be similar to what you are doing.
interface
TMyComponent = class(TCustomControl)
private
embeddedButton: TButton;
fOnButtonClick: TNotifyEvent;
procedure EmbeddedButtonClick(Sender: TObject);
protected
procedure DoEmbeddedButtonClick; virtual;
public
constructor Create(AOwner: TComponent); override;
published
property OnButtonClick: TNotifyEvent read fOnButtonClick write fOnButtonClick;
end;
implementation
// Attach embedded button event handler onto embedded button
constructor TMyComponent.Create(AOwner: TComponent);
begin
// .. other code
embeddedButton.OnClick := EmbeddedButtonClick;
// .. more code
end;
// EmbeddedButtonClick fires internal overridable event handler;
procedure TMyComponent.EmbeddedButtonClick(Sender: TObject);
begin
// If you want to preserve the Sender, extend this method
// with a sender argument.
DoEmbeddedButtonClick;
end;
procedure TMyComponent.DoEmbeddedButtonClick;
begin
// Optionally if you need to do additional internal work
// when the button is clicked, you can do it here.
// Check if event handler has been assigned
if Assigned(fOnButtonClick) then
begin
// Fire user-assigned event handler
fOnButtonClick(Self);
end;
end;
I need to write a TQuery descendant with an override on onBeforePost event where I should check the state if its dsInsert or dsEdit or not... and allow or not the post to proceed, but I need someone with experience with custom components to double-check it.
It's been long since I created my components and I'm a bit rusty. Can you take a look at what I got and tell me if I am doing it right?
Here is my code for the component
unit MxQuery;
interface
uses
SysUtils, Classes, DB, DBTables;
type
TMxQuery = class(TQuery)
procedure DoBeforePost; override;
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
constructor Create(AOwner:TComponent); override;
end;
procedure Register;
implementation
constructor TMxQuery.Create(AOwner:Tcomponent);
begin
inherited create(AOwner);
end;
procedure Register;
begin
RegisterComponents('Samples', [TMxQuery]);
end;
procedure TMxQuery.DoBeforePost;
begin
case self.DataSource.State of
dsEdit,dsInsert:
begin
//Do nothing or other stuff
end;
else
begin
self.DataSource.DataSet.Cancel;
Abort;
end;
end;
inherited;
end;
end.
Thanks
Imho, this question fits https://codereview.stackexchange.com/ much better.
Anyway, let me point something out:
Your code should be working.
As #SirRufo said, you unnecessarily raised visibility of method DoBeforePost to published. Look for this this method in declaration TQuery or one of its ancestors. Override the method with the same visibility found there.
Constructor TMxQuery.Create is not needed, as it does not add anything.
I have created a component with TFrame as ancestor with the following code:
type
TCHAdvFrame = class(TFrame)
private
{ Private declarations }
FOnShow : TNotifyEvent;
FOnCreate : TNotifyEvent;
protected
procedure CMShowingChanged(var M: TMessage); message CM_SHOWINGCHANGED;
public
{ Public declarations }
constructor Create(AOwner: TComponent) ; override;
published
property OnShow : TNotifyEvent read FOnShow write FOnShow;
property OnCreate : TNotifyEvent read FOnCreate write FOnCreate;
end;
implementation
{$R *.dfm}
{ TCHAdvFrame }
procedure TCHAdvFrame.CMShowingChanged(var M: TMessage);
begin
inherited;
if Assigned(OnShow) then
begin
ShowMessage('onShow');
OnShow(self);
end;
end;
constructor TCHAdvFrame.Create(AOwner: TComponent);
begin
ShowMessage('OnCreate1');
inherited ;
ShowMessage('OnCreate2');
if Assigned(OnCreate) then
begin
ShowMessage('OnCreate3');
OnCreate(self);
end;
I have registered the new component and did some tests. ShowMessage('OnCreate1'); and ShowMessage('OnCreate2'); are correctly executed but not ShowMessage('OnCreate3');
This prevents to add code during the implementation of a new instance of TCHAdvFrame.
Why is it and how can I solve this ?
A frame is streamed in as part of its ultimate owner's constructor. Typically that will be a form. The form processes the .dfm file. It encounters new objects and creates them. Then it sets the properties of the newly created object. So, the frame's properties are set after its constructor returns.
This is the reason that TFrame does not have an OnCreate event. There is simply no way for the event to be fired because the event by necessity is assigned too late. The VCL designers omitted this event for the very same reason that led you to ask this question. So I do suspect that you likewise should not add this event.
How to solve this? Hard to say for sure unless we had a more detailed description of the problem. Perhaps you could override the frame's Loaded method to good effect. Or perhaps all you need to do is let consumers of your component override the constructor in their derived frames.
Related reading: http://delphi.about.com/od/delphitips2007/qt/tframe_oncreate.htm
I'm writing simple component. What I want to achieve is that my MethodOptions will change in Object Inspector according to Method I choose.
Something like this:
So far I coded:
TmyMethod = (cmFirst, cmSecond);
TmyMethodOptions = class(TPersistent)
published
property SomethingInBase: boolean;
end;
TmyMethodOptionsFirst = class(TmyMethodOptions)
published
property SomethingInFirst: boolean;
end;
TmyMethodOptionsSecond = class(TmyTMethodOptions)
published
property SomethingInSecond: boolean;
end;
TmyComponent = class(TComponent)
private
fMethod: TmyMethod;
fMethodOptions: TmyMethodOptions;
procedure ChangeMethod(const Value: TmyMethod);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Method: TmyMethod read fMethod write ChangeMethod default cmFirst;
property MethodOptions: TmyMethodOptions read fMethodOptions
write fMethodOptions;
end;
implementation
procedure TmyComponent.ChangeMethod(const Value: TmyMethod);
begin
fMethod := Value;
fMethodOptions.Free;
// case...
if Value = cmFirst then
fMethodOptions := TmyMethodOptionsFirst.Create
else
fMethodOptions := TmyMethodOptionsSecond.Create;
// fMethodOptions.Update;
end;
constructor TmyComponent.Create(AOwner: TComponent);
begin
inherited;
fMethodOptions := TmyMethodOptions.Create;
fMethod := cmFirst;
end;
destructor TmyComponent.Destroy;
begin
fMethodOptions.Free;
inherited;
end;
Of course it does almost nothing (except hanging IDE) and I don't have any starting point where to search the suitable knowledge to achieve this.
If I understand correctly I believe that this the same technique the Developer Express implemented in their Quantum Grid component, for dynamically showing different properties for various field types in the grid. There is an explanation of the mechanism here: Technology of the QuantumGrid
I am trying to create a custom control based on the TCustomComboBox in Delphi 2007, But I am stuck on the first hurdle.
I am trying to override the way the drop down is displayed, primarally the text that is displayed, looking at the source for TCustomComboBox in stdctrls.pas it looks like i just need to override DrawItem but it is not working, as the code in my overridden method is never executed.
I have looked a several open source components source code to see how they do it, but I am still at a loss.
Here is what I have so far (not much admittedly)
type
TKeyValueComboBox = class(TCustomComboBox)
private
{ Private declarations }
//FColumns:Integer;
protected
{ Protected declarations }
procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
end;
And
procedure TKeyValueComboBox.DrawItem(Index: Integer; Rect: TRect;
State: TOwnerDrawState);
begin
TControlCanvas(Canvas).UpdateTextFlags;
if Assigned(OnDrawItem) then OnDrawItem(Self, Index, Rect, State)
else
begin
Canvas.FillRect(Rect);
Canvas.TextOut(Rect.Left + 2, Rect.Top, Items[Index]+'-HELLO');
end;
end;
Does anyone know what method I need to use to get my overridden version of fire? or what I am doing wrong?
Any help would be appreciated.
There also is a property that has to be set, from memory it's DrawingStyle := dsCustomDraw
Put that in the constructor or Loaded.
Did you enable owner-drawing? By default it's deactivated. Try to get the custom drawing work with a standard combo box and create your custom control afterwards, applying all the necessary settings.