[2 days left] What’s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now

x
?
Solved

Override delphi events

Posted on 2010-09-16
8
Medium Priority
?
1,523 Views
Last Modified: 2013-11-23
Hello experts,

I want to find out how to override existing events in the following manner.

I have created a "manager object" for tables and datasets.  The manager object does many similar things happening to all my connected tables and datasets.

Therefore I want to assign for example a "before post" that will be executed ON TOP of the before post I put in my table.

Short saying I want to have something like...

procedure TMyManagerClass.BeforePost(dataset: TDataSet); override;
begin
     // do the things that I keep doing all the time

     inherited; // <--do whatever extra functionality user defines on his normal "BeforePost" method
end;

procedure TMyManagerClass.DblClick(view: TcxGridTableView); override;
begin
     // do the things that keep happening on the grid

    inherited; //<-- if user defines extra funtionality on the dblclick, do it now
end;

To make it more simple, I want to do FIXED ADDITIONAL OPERATION to the one specified by the event the user can define, but do it through a manager class that contains a constructor that receives one dataset and one TcxTableView.
0
Comment
Question by:Ioannis Anifantakis
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
  • 2
  • +1
8 Comments
 
LVL 6

Author Comment

by:Ioannis Anifantakis
ID: 33694684
Ok, no solutions...

In the meantime, I made the unit that handles that myself and I paste it here for those who might be interested on such a functionality.

The class constructor takes DevExpress tableView or bandedView, and a dataset.

I provide a manager class for a grid/dataset combination. When browsing the grid, user doesn't have auto edit (OptionsBehavior.ImmediateEditor=false), but has auto-increment search (OptionsBehavior.IncSearch=true). When user starts editing, auto-edit comes and autoincrement leaves (the opposite). When inserting at either TableView or BandedView it moves the cursor to the leftmost cell for editing.

It can take on the constructor either TableView or BandedView. so it works both for bands or tables.

Its an object that has to be manually created and takes (view, dataset) on the constructor. Its freed if you put a "free" call to the object at the "Close" of your form. You assign one such object for each tableview or bandedview you wish to manage.

On top of all that, you can easily get from the manager class whether the dataset is in edit or browsing mode by making a call to the "isEditing" function.

Enjoy
UcxGridDataSets.pas
0
 
LVL 32

Expert Comment

by:Ephraim Wangoya
ID: 33697656

What happens to your object if View is destroyed by its owner?

What if your object is destroyed?, Your dataset is suddenly pointing at events that don't exist anymore, what of the original events, they are all lost.
AV
0
 
LVL 6

Author Comment

by:Ioannis Anifantakis
ID: 33699723
Dear ewangoya,

You are right on few things, and wrong on others.

Firstly, the code provides solution to the above problem without inheriting an object as my question dictates.
Secondly, exactly for the reasons you stated, incase of a foundamental change in dataset object that deprecates all the known events (which is impossible by the way), instead of changing all your code, you simply chane this unit's code and your system keeps running.

Finally, ofcourse you have to create the object manually, and free it manually at the "close" event of your form.

I provided this as it was my solution, so that people who might come to the same issue in the future know how to implement the "EXTRA" code for their events.  In  other words help the delphi community of the EE.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 6

Author Comment

by:Ioannis Anifantakis
ID: 33699735
also, if you believe you can enchant this to something better, please paste it here.
Thank you
0
 
LVL 38

Accepted Solution

by:
Geert Gruwez earned 1000 total points
ID: 33700078
there is something more easy than what you use
it's called subclassing
you can redefine a object type within a unit
or using a extra unit as last in the uses clause

this does some autoassigning ... (didn't test the code)
if you want your own event before or after calling the default :

unit YourUnit;

interface

uses Classes, Windows, etc ..., DBTables;

type
  TQuery = class(DBTables.TQuery)
  protected
    function FindGridView: TcxGridView; virtual;
    procedure DoAfterPost(aDataset: TDataset); override;
  end;

function TQuery.FindGridView: TcxGridView;
var
  frm: TForm;
  I: Integer;
begin
  Result := nil;
  // Only works if query was created with a owner  
  frm := TForm(Self.Owner);
  if Assigned(frm) then
    for I := 0 to frm.ComponentCount-1 do
      if frm.Components[I] is TcxGridTableView then
        if TcxGridView(frm.Components[I]).DataController.Dataset = Self then
        begin
          Result := TcxGridView(frm.Components[I]);
          Exit;
        end;
end;

procedure TQuery.DoAfterPost(aDataset: TDataset);
var gv: TcxGridView;
begin
  // Do something before handler
  //
  gv := FindGridView;
  if Assigned(gv) then
    if gv.Controller.IsEditing then
    begin
      // stop editing
      gv.Controller.EditingController.EndEdit(True);
    end;
  inherited DoAfterPost(aDataset);
  // Do something after handler
end;
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 33700099
o ... be aware of devexpress and editing

it works with listeners ...
you can't always stop editing in certain places, sometimes it's asynchronous using messages
0
 
LVL 5

Expert Comment

by:briangochnauer
ID: 33719975
I did something similar in that I wanted to 'log' the opening and closing of the dataset so I assigned ALL of the different tables or queries to the same AfterOpen event.
Then inside that event you'll have to figure out what dataset component has called it;
I hope you get the 'jist' of this.
This becomes a *Central* AfterOpen event .
 
procedure TDataModuel1.ClientDatasetAfterOpen(DataSet: TDataSet);
var s :string; t:TComponent;
begin
  s := Dataset.Name;

  try
    t := FindComponent(s);
    if Assigned(t) and
       ((TClientDataset(t).FileName <> '') or
       (not TClientDataset(t).ConnectionBroker.Connected)) then
     if (TClientDataset(t).FileName <> '') then
     s := s+' locally ('+TClientDataset(t).FileName+')'
      else s := s+' running as disconnected dataset from ('+
          TSocketConnection(TClientDataset(t).ConnectionBroker.Connection).Host+')'
     else s := s+' remotely ('+TSocketConnection(TClientDataset(t).ConnectionBroker.Connection).Host+')';
  except
    on E:Exception do
    begin
      LogFile.LogMessageSt('AfterOpen Exception: '+e.message,1);
      s := Dataset.Name;
    end;
  end;
  LogFile.LogMessageSt(s + ' opened.',3);
end;
 
0
 
LVL 32

Assisted Solution

by:Ephraim Wangoya
Ephraim Wangoya earned 1000 total points
ID: 33931166
@ioannisa

First doing it Geert's way is pretty good

Now,
If you create a component or object for others to use, they will not always use it the way you do or expect. You assume that the Object will be destroyed before the View and Dataset or vice versa but this may not be the case

I have modified your code just abit, note the inclusion of Notification and the test CanNotify. I changed it from TObject to TComponent. Always protect your code from the unexpected which was the point I was trying to put forward in my previous post. You don't need function IsEditing, just use a property.

Just take note of these points when you create components in future
type
  TcxGridDataSetsManager = class(TComponent)
  private
    FTableView: TcxGridTableView;
    FDataset: TDataSet;
    FEditing: Boolean;

    FAfterCancel: TDataSetNotifyEvent;
    FAfterDelete: TDataSetNotifyEvent;
    FAfterEdit: TDataSetNotifyEvent;
    FAfterInsert: TDataSetNotifyEvent;
    FAfterPost: TDataSetNotifyEvent;

    procedure setGridEditable(view: TcxGridTableView; setEditable: boolean);

    procedure AfterCancel(DataSet: TDataSet);
    procedure AfterDelete(DataSet: TDataSet);
    procedure AfterEdit(DataSet: TDataSet);
    procedure AfterInsert(DataSet: TDataSet);
    procedure AfterPost(DataSet: TDataSet);

    function CanNotify: Boolean;
    procedure RestoreEvents;
  protected
    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;
  public
    Constructor Create(AOwner: TComponent; view: TcxGridTableView; DataSet: TDataSet); override;
    Destructor Destroy; override;
    property Editing: Boolean read FEditing;
  end;

implementation

{ TcxGridDataSets }

function TcxGridDataSetsManager.CanNotify: Boolean;
begin
  Result := Assigned(FTableView) and Assigned(FDataset);
end;

Constructor TcxGridDataSetsManager.Create(AOwner: TComponent; view: TcxGridTableView; DataSet: TDataSet);
begin
    inherited Create(AOwner);
    FTableView:=view;

    FDataset:=DataSet;

    // if some user had assigned code to any of these events
    // remember it by storing this reference to "prv" events.
    FAfterCancel:=FDataset.AfterCancel;
    FAfterDelete:=FDataset.AfterDelete;
    FAfterEdit:=FDataset.AfterEdit;
    FAfterInsert:=FDataset.AfterInsert;
    FAfterPost:=FDataset.AfterPost;

    // assign the new events to the following dataset methods
    FDataset.AfterCancel:=AfterCancel;
    FDataset.AfterDelete:=AfterDelete;
    FDataset.AfterEdit:=AfterEdit;
    FDataset.AfterInsert:=AfterInsert;
    FDataset.AfterPost:=AfterPost;

    // initially we want to search data, so we initialize our
    // incremental search and our auto-edit to non-editing mode.
    FEditing:=false;
    setGridEditable(FTableView, FEditing);
end;

destructor TcxGridDataSetsManager.Destroy;
begin
  Destroying;
  RestoreEvents;
  inherited;
end;

procedure TcxGridDataSetsManager.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if Operation = opRemove then
  begin
    if Component = FTableView then
      FTableView := nil;

    if FComponent = FDataset then
    begin
      FAfterCancel:=nil;
      FAfterDelete:=nil;
      FAfterEdit:=nil;
      FAfterInsert:=nil;
      FAfterPost := nil;
      FDataset := nil;
    end;
  end;
end;

procedure TcxGridDataSetsManager.RestoreEvents;
begin
  if Assigned(FDataset) and not (csDestroying in FDataset.ComponentState) then
  begin
    FDataset.AfterCancel:=FAfterCancel;
    FDataset.AfterDelete:=FAfterDelete;
    FDataset.AfterEdit:=FAfterEdit;
    FDataset.AfterInsert:=FAfterInsert;
    FDataset.AfterPost:=FAfterPost;
  end;
end;

(* make immediate editing or incrementally searchable the table or banded view *)
procedure TcxGridDataSetsManager.setGridEditable(view: TcxGridTableView;
  setEditable: boolean);
begin
  if CanNotify then
  begin
    view.OptionsBehavior.ImmediateEditor:=setEditable;
    view.OptionsBehavior.IncSearch:=not setEditable;
  end;
end;

(* code run BEFORE the actual AfterCancel method defined by user *)
procedure TcxGridDataSetsManager.AfterCancel(DataSet: TDataSet);
begin
    // after canceling -> stop editing and go to incremental serach mode
    FEditing := false;

    if CanNotify then
    begin
      setGridEditable(FTableView, FEditing);

      // call normally assigned AfterCancel method (if any) defined by user on his dataset
      if Assigned(FAfterCancel) then
        FAfterCancel(DataSet);
    end;
end;

(* code run BEFORE the actual AfterDelete method defined by user *)
procedure TcxGridDataSetsManager.AfterDelete(DataSet: TDataSet);
begin
    // after deleting record -> stop editing and go to incremental serach mode
    FEditing:=false;
    if CanNotify then
    begin
      setGridEditable(FTableView, FEditing);

      // call normally assigned AfterDelete method (if any) defined by user on his dataset
      if Assigned(FAfterDelete) then
          FAfterDelete(DataSet);
    end;
end;

(* code run BEFORE the actual AfterEdit method defined by user *)
procedure TcxGridDataSetsManager.AfterEdit(DataSet: TDataSet);
begin
    // after editing record -> stop incremental serach and start editing
    FEditing:=true;
    if CanNotify then
    begin
      setGridEditable(FTableView, isEditing);

      // call normally assigned AfterEdit method (if any) defined by user on his dataset
      if Assigned(FAfterEdit) then
          FAfterEdit(DataSet);
    end;
end;

(* code run BEFORE the actual AfterInsert method defined by user *)
procedure TcxGridDataSetsManager.AfterInsert(DataSet: TDataSet);
begin
    // after inserting new record -> stop incremental serach and start editing
    FEditing:=true;
    if CanNotify then
    begin
      setGridEditable(FTableView, isEditing);

      // when inserting a new record, go to the leftmost column to start inserting
      FTableView.Controller.FocusedItemIndex:=0;

      // call normally assigned AfterInsert method (if any) defined by user on his dataset
      if Assigned(FAfterInsert) then
          FAfterInsert(DataSet);
    end;
end;

(* code run BEFORE the actual AfterPost method defined by user *)
procedure TcxGridDataSetsManager.AfterPost(DataSet: TDataSet);
begin
    // after posting record changes -> stop editing and go to incremental serach mode
    FEditing:=false;
    if CanNotify then
    begin
      setGridEditable(FTableView, FEditing);

      // call normally assigned AfterPost method (if any) defined by user on his dataset
      if Assigned(FAfterPost) then
          FAfterPost(DataSet);
    end;
end;

Open in new window

0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In response to a need for security and privacy, and to continue fostering an environment members can turn to for support, solutions, and education, Experts Exchange has created anonymous question capabilities. This new feature is available to our Pr…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

656 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question