I have a TDBGrid component. I need to catch the event triggered when I'm resizing a column of the grid.
the only place to get an events seems to be overriding ColWidthChanged...
type
TDBgrid=Class(DBGrids.TDBGrid)
private
FColResize:TNotifyEvent;
procedure ColWidthsChanged; override;
protected
Property OnColResize:TNotifyEvent read FColResize Write FColResize;
End;
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
DBGrid1: TDBGrid;
ADODataSet1: TADODataSet;
DataSource1: TDataSource;
procedure FormCreate(Sender: TObject);
private
procedure ColResize(Sender: TObject);
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TDBgrid }
procedure TDBgrid.ColWidthsChanged;
begin
inherited;
if Assigned(FColResize) then FColResize(self);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DBgrid1.OnColResize := ColResize;
end;
procedure TForm1.ColResize(Sender:TObject);
begin
Caption := FormatDateTime('nn:zzz',now) ;
end;
you need to create a descendent of TDBGrid and implement the event by yourself. Something like this:
unit MyDBGrid;
interface
type
TMyDBGrid = class(TDBGrid)
private
FOnColResize: TNotifyEvent;
protected
procedure ColWidthsChanged; override;
public
published
property OnColResize: TNotifyEvent read FOnColResize write FOnColResize;
end;
implementation
{ TMyDBGrid }
procedure TMyDBGrid.ColWidthsChanged;
begin
inherited;
if (Datalink.Active or (Columns.State = csCustomized)) and
AcquireLayoutLock and Assigned(FOnColResize) then
FOnColResize(Self);
end;
end.
this should work, I don't have time now to test it.
Related
I'm new at SO, so forgive me if my question isn't in the right place or been answered before.
The questions is about multi-threading with Delphi 10.4.
I'm getting Access Violation error on my app, here is a very simple example:
type
myThread = class(TThread)
protected
procedure Execute; override;
end;
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
mySideTask : myThread;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
with mySideTask.Create do
FreeOnTerminate:=True
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if mySideTask<>nil then
begin
mySideTask.Terminate;
mySideTask.WaitFor;
FreeAndNil(mySideTask);
end;
end;
{ myThread }
procedure myThread.Execute;
begin
Synchronize(
procedure
begin
Form1.Memo1.Lines.Add('running my side task')
end);
end;
No error if I don't create an instance of the thread (which is confusing me):
procedure TForm1.Button1Click(Sender: TObject);
begin
myThread.Create
end;
Can you please let me know what am I missing.
The code in Button1Click() is wrong. You are calling Create() as an instance method on your mySideTask variable, but it is not pointing at a valid object instance. You need to instead call Create() as a constructor on the class type itself.
Try this instead:
procedure TForm1.Button1Click(Sender: TObject);
begin
mySideTask := myThread.Create(False{True});
//mySideTask.FreeOnTerminate := True;
//mySideTask.Start;
end;
Notice I commented out the handling of FreeOnTerminate=True. The reason for that is because that setting is meant for create-and-forget type of threads. The thread will destroy itself after its Execute() method exits. So it is not safe to call WaitFor() or Free() on a thread that could destroy itself at any moment.
If you want to use FreeOnTerminate=True, then the code should look more like this instead:
type
myThread = class(TThread)
protected
procedure Execute; override;
end;
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
mySideTask : myThread;
procedure SideTaskTerminated(Sender: TObject);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
mySideTask := myThread.Create(True);
mySideTask.FreeOnTerminate := True;
mySideTask.OnTerminated := SideTaskTerminated;
mySideTask.Start;
end;
procedure TForm1.SideTaskTerminated(Sender: TObject);
begin
mySideTask := nil;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if mySideTask <> nil then
begin
mySideTask.FreeOnTerminate := False;
mySideTask.Terminate;
mySideTask.WaitFor;
FreeAndNil(mySideTask);
end;
end;
{ myThread }
procedure myThread.Execute;
begin
Synchronize(
procedure
begin
Form1.Memo1.Lines.Add('running my side task')
end);
end;
I have this class to handle my webcam and want know how can stop the webcam started in a separated thread. Camera.Destroy not is working and the camera keep on.
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Panel1: TPanel;
Image1: TImage; // To load camera Bitmap from stream
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TCameraThread = class(TThread)
protected
procedure Execute; override;
end;
var
Form1: TForm1;
implementation
uses
Webcam;
{$R *.dfm}
procedure TCameraThread.Execute;
begin
Camera := TCamera.Create(Form1.Panel1);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
mCamera: TCameraThread;
begin
mCamera := TCameraThread.Create(False);
mCamera.Resume;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if Assigned(Camera) then
Camera.Destroy;
end;
end.
I have a TListView and a TObjectList. I bind TFoo.value to Item.Caption.
I write a procedure "AfterScroll" with a showmessage inside. I connect the procedure on TBindSourceAdapter.AfterScroll.
I run this program and I have just one showmessage.
If I replace TListView by TStringGrid, I have the showmessage on each lines.
type
TFoo = class
private
FValue: string;
public
constructor create(sValue: string);
property Value: string read FValue write FValue;
end;
TForm5 = class(TForm)
PrototypeBindSource1: TPrototypeBindSource;
StringGrid1: TStringGrid;
BindingsList1: TBindingsList;
LinkGridToDataSourcePrototypeBindSource1: TLinkGridToDataSource;
ListView1: TListView;
LinkFillControlToField1: TLinkFillControlToField;
procedure PrototypeBindSource1CreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
private
{ Déclarations privées }
ListFoo: TObjectList<TFoo>;
procedure AfterScrool(Adapter: TBindSourceAdapter);
public
{ Déclarations publiques }
constructor create(AOwner: TComponent); override;
end;
var
Form5: TForm5;
implementation
{$R *.fmx}
{ TForm5 }
procedure TForm5.AfterScrool(Adapter: TBindSourceAdapter);
begin
ShowMessage('kk');
end;
constructor TForm5.create(AOwner: TComponent);
begin
ListFoo := TObjectList<TFoo>.create();
ListFoo.Add(TFoo.create('Test'));
ListFoo.Add(TFoo.create('Test 1'));
ListFoo.Add(TFoo.create('Test 2'));
ListFoo.Add(TFoo.create('Test 3'));
inherited create(AOwner);
end;
procedure TForm5.PrototypeBindSource1CreateAdapter(Sender: TObject; var ABindSourceAdapter: TBindSourceAdapter);
begin
ABindSourceAdapter := TListBindSourceAdapter<TFoo>.create(self, ListFoo);
ABindSourceAdapter.AfterScroll := AfterScrool;
end;
{ TFoo }
constructor TFoo.create(sValue: string);
begin
inherited create;
FValue := sValue;
end;
end.
It is possible to connect an "AfterScroll" event on a TListView ?
I found, we need to bind "*" on "Synch" property of TListView
Is there any event that determines, if the mouse is hovering above an edit box? Basically, I want to show a hint/help for the user, but I want to display an image and simple instructions. What would be the best way to proceed?
Thanks for any help
Use the OnMouseEnter and OnMouseLeave events. In the event handlers, you can set the visibility of a Label or simliar control with the hint text. In the example, I took an empty VCL form and inserted a TEdit and a TLabel. I implemented the OnMouseMEnter and the OnMouseLeave events:
TForm1 = class(TForm)
Edit1: TEdit;
Label1: TLabel;
procedure Edit1MouseEnter(Sender: TObject);
procedure Edit1MouseLeave(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Edit1MouseEnter(Sender: TObject);
begin
Label1.Visible:=True;
end;
procedure TForm1.Edit1MouseLeave(Sender: TObject);
begin
Label1.Visible:=False;
end;
Another solution could be to use the OnMouseEnter and OnMouseLeave events.
This is a sample found on Embarcadero:
type
TForm1 = class(TForm)
Button1: TButton;
StatusBar1: TStatusBar;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
procedure DisplayHint(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ Here is the implementation of the OnHint event handler }
{ It displays the application’s current hint in the status bar }
procedure TForm1.DisplayHint(Sender: TObject);
begin
StatusBar1.SimpleText := GetLongHint(Application.Hint);
end;
{ Here is the form’s OnCreate event handler. }
{ It assign’s the application’s OnHint event handler at runtime }
{ because the Application is not available in the Object Inspector }
{ at design time }
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnHint := DisplayHint;
end;
You can use special tag on HINT property of TLabel, then manage the output as you need.
As an example, given the code extract below, I would like to define a breakpoint that triggers whenever the object field value changes and optionally, breaks on a condition (False or True in this case).
type
TForm1 = class(TForm)
EnableButton: TButton;
DisableButton: TButton;
procedure EnableButtonClick(Sender: TObject);
procedure DisableButtonClick(Sender: TObject);
private
FValue: Boolean; // <== Would like to define a breakpoint here whenever FValue changes.
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.DisableButtonClick(Sender: TObject);
begin
FValue := False;
end;
procedure TForm1.EnableButtonClick(Sender: TObject);
begin
FValue := True;
end;
Run the application under the debugger,
select 'Run' from the IDE menu then select 'Add Breakpoint' at the very bottom, then 'Data Breakpoint...'.
enter 'Form1.FValue' as input to the 'Adress:' field. You can also set your condition in the same dialog.
Some additional information thanks to Sertac answer and comment from David.
One can define a breakpoint based on changes in an array item with a condition.
In this case the data breakpoint is defined as follow:
Form1.FBooleans[0] = True
Code extract:
type
TBooleanArray = array of Boolean;
TForm1 = class(TForm)
EnableButton: TButton;
DisableButton: TButton;
procedure EnableButtonClick(Sender: TObject);
procedure DisableButtonClick(Sender: TObject);
private
FBooleans: TBooleanArray; // Breakpoint defined here with the condition
public
constructor Create(AOwner: TComponent); override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TForm1.Create(AOwner: TComponent);
var
AIndex: Integer;
begin
inherited;
SetLength(FBooleans, 3);
for AIndex := 0 to Length(FBooleans) - 1 do
begin
FBooleans[AIndex] := (AIndex mod 2) = 1;
end;
end;
procedure TForm1.DisableButtonClick(Sender: TObject);
begin
FBooleans[0] := False;
end;
procedure TForm1.EnableButtonClick(Sender: TObject);
begin
FBooleans[0] := True; // Beakpoint stops here on condition.
end;