Icon View Thread

The following is the text of the current message along with any replies.
Messages 11 to 20 of 22 total
Thread Waiting For Completion
Tue, Sep 13 2016 1:36 PMPermanent Link

erickengelke

Avatar

Trinione wrote:

Erick wrote:
<< In the after load event, you cycle through tdataset  using tdataset.first, then tdataset.next until you either find your desired results or you hit tdataset.eof. >>


>For instance, from the code below - from a function in another program, how can the value of recFound be returned?

The easiest way is to set the 'result' pseudo variable which is what gets returned.


procedure TdmDataModule.dsCustomerAfterLoad(Sender: TObject);
var
 recFound: boolean;

begin
 recFound := False;

 if dsCustomer.RowCount > 0 then
   recFound := True;
 result := recFound ;   // <<<<<<< HERE
end;
Tue, Sep 13 2016 3:11 PMPermanent Link

Trinione

erickengelke wrote:

Trinione wrote:

Erick wrote:
<< In the after load event, you cycle through tdataset  using tdataset.first, then tdataset.next until you either find your desired results or you hit tdataset.eof. >>


>For instance, from the code below - from a function in another program, how can the value of recFound be returned?

<< The easiest way is to set the 'result' pseudo variable which is what gets returned.

procedure TdmDataModule.dsCustomerAfterLoad(Sender: TObject);
var
 recFound: boolean;

begin
 recFound := False;

 if dsCustomer.RowCount > 0 then
   recFound := True;
 result := recFound ;   // <<<<<<< HERE
end;
>>

Erick:
As dsAfterLoad event is a Procedure and not a Function, setting 'result' results in an error stating the referenced variable does not exist.
Tue, Sep 13 2016 3:12 PMPermanent Link

Trinione

<< I set a callback for afterLoad to a local proc in the calling form. Still think it's a bit ugly but it seems to work. >>

What Squiffy wrote is what I am trying to achieve.
Tue, Sep 13 2016 3:17 PMPermanent Link

Trinione

Trinione wrote:
<< What Squiffy wrote is what I am trying to achieve. >>

Just found the chapter in the Manual re: Asynchronous Calls. Reading it now.....
Tue, Sep 13 2016 4:04 PMPermanent Link

Trinione

Trinione wrote:
<< Just found the chapter in the Manual re: Asynchronous Calls. Reading it now..... >>

The following works. If no one comments otherwise, I would assume this is the way to accomplish this in EWB.

In calling function:
------------------------------
 dsCustomer.Params.Add('id=' + cid);
 async(Database.LoadRows(dsCustomer));

 if dsCustomer.RowCount > 0 then
  result := dsCustomer.Columns['id'].AsInteger;
------------------------------
Tue, Sep 13 2016 4:28 PMPermanent Link

Raul

Team Elevate Team Elevate

On 9/13/2016 4:04 PM, Trinione wrote:
> Trinione wrote:
> The following works. If no one comments otherwise, I would assume this is the way to accomplish this in EWB.
> In calling function:
> ------------------------------
>   dsCustomer.Params.Add('id=' + cid);
>   async(Database.LoadRows(dsCustomer));
>
>   if dsCustomer.RowCount > 0 then
>    result := dsCustomer.Columns['id'].AsInteger;
> ------------------------------

I'm surprised this works - that does not make sense to me at all.

I can see this only working if your dsCustomer has some data already
when this function starts.

Async call results the function call to be queued up for the UI thread
to run next time it processes messages - which is after this function
has finished and exited.

Callback is the only way to accomplish this properly AFAIK (or timers
and modal "please wait" typoe dialog or such but then you need need to
some additional tracking to deal with failures and if things take more
time that anticiapted and timer fires).

Raul
Tue, Sep 13 2016 5:34 PMPermanent Link

Trinione

Rauk wrote:
<< Callback is the only way to accomplish this properly AFAIK >>

How are Callbacks done?

More specifically, how can a callback be used in this case from a Function calling a dataset's OnLoad event 'result'?
Tue, Sep 13 2016 10:12 PMPermanent Link

Raul

Team Elevate Team Elevate

On 9/13/2016 5:34 PM, Trinione wrote:
> How are Callbacks done?
> More specifically, how can a callback be used in this case from a Function calling a dataset's OnLoad event 'result'?

It really depends what you actually want to achieve and what your
current code logic is.

Few options i can think of

1. If all your logic is in the same unit (for example on the form) then
you simply need to break your code into 2 parts:

- part 1 runs forst and call loadrows at the end
- part 2 is called from AfterLoad event itself

for Example

procedure TForm1.CustomerAfterLoad(Sender: TObject);
begin
  MyFunction2;
end;

This is not really a callback but just way one has to do async -
splitting your code into 2 functions.


2. Maybe you want to have a generic unit/class that handles all the data
loads so you simply need to call correct callback. One way to handle
this is with something like this

a. declare a callback function type

type
   TMyCallBackFunc = procedure (RecFound:boolean) of object;

b. define actual callback function - this could be set by any other code
since it's public

   public
      FCustomerLoadCallback:TMyCallBackFunc;

c. and when doing loadrows also assign callback

  FCustomerLoadCallback := HandleCustomerLoadDone; //this is my function

d. and in your AfterLoad handler do

procedure MyGenericAfterLoad(Sender: TObject);
begin
 if TDataSet(Sender).DataSetName = 'Customer' then
 begin
   if assigned(FCustomerLoadCallback) then
   FCustomerLoadCallback(true);
 end;
 //could check other datasets here ...
end;

this is fairly simplistic fixed callback logic but works well if you
simplty need a generic module to handle dataaset loading and allow few
callback functions to be called.



3. This is nicest IMHO and most genric since you can have dataset carry
callback around with it so it's self contained and thus the actual
dataset afterload events can be very generic and they will just call
proper callback functions if you have assigned them.

Use the Data element and just wrap it in class.

You need to make sure that all your callbacks and such are "alive" -
i.e. do not assign a callback on a form for example that might get
destroyed while LoadRows is still executing.


a.  define callback function type again and wrapper class
type
   TMyCallBackFunc = procedure (RecFound:boolean) of object;
   TMyCallBackObject = class(TObject)
      FuncCallback:TMyCallBackFunc;
   end;

b. when customer dataset is created also associate the Data element -
i'm doing it all when loading rows but your app logic will defined how
to run this

   myCB := TMyCallBackObject.Create;
   myCB.FuncCallback := HandleCustomerLoadDone; //assign callback
   Customer.Data := myCB;  //assign your class to dataset
   database.loadrows(Customer);

c. in afterload you would do something like this

   dsCB := TMyCallBackObject(TDataSet(Sender).Data);
   if assigned(dsCB) then
   begin
      if assigned(dsCB.FuncCallback) then
        dsCB.FuncCallback(true);
   end;

Note that in all of these cases you should also handle OnLoadError event
and act appropriately (again you can have callback for that).


Let me know if any of this helps and if you have any other questions

Raul
Wed, Sep 14 2016 12:33 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com


<< I mean how can I get to the calling Function program a value, True or False in this case - but it could be a string or integer, and value really. >>

Just add a public Boolean member variable (CustomersFound) to your database instance, and then set the variable to False in the BeforeLoad, and then set it accordingly in the AfterLoad.  Or, you could do it way easier and just have the other areas of the application test the RowCount property of the dataset in question.  The functionality is equivalent.

I sense that what you're looking for is a way to make this process synchronous, which will *not* be possible in a browser environment.

Tim Young
Elevate Software
www.elevatesoft.com
Wed, Sep 14 2016 5:10 PMPermanent Link

Trinione

Raul:
Thank you for your detailed response. It has made me realise this is not as simple as I initially thought as the coding is just out of reach for me as a developing Object Pascal developer.

Of the three, I like Option 3 and shall give it a go. I shall use the included sample Customer table as a test.

Basically, this is what I need to accomplish:
1- Use an unbound Grid with checkboxes in column 1 and RequestedCustomerID value in Column2.
2 - Scroll thru the rows and for those items selected check the RequestedCustomerID from the grid's Column2.
3 - Create tabs for each selected Customer IDs after checking that the Customer ID record does in fact exist.

NOTE, the grid is not created from the database, so the customer ID number may or may not exist in the database - hence the FindCustomerID check that is the reason for my wanting to know about this Callback ability.

Thus far, (similar to your Suggestion #1) I am using a direct call back to a function to create that tabs I have the ability to check on one item by double-clicking, haven't tested in a loop as yet.
« Previous PagePage 2 of 3Next Page »
Jump to Page:  1 2 3
Image