RTC Forums
November 24, 2024, 09:28:49 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: RTCHTTPClient and main form to datamodule access to events  (Read 7683 times)
jonb2
Newbie
*
Posts: 36


« on: April 24, 2012, 06:09:27 PM »

Good Evening Danijel & Crew

Yup. Got my knickers in a twist again. Again, it's the events getting one over on me.

I am trying to control an RTCClient on a DM from the main form.

Setup thus, from a button on the main form:

    dm_apitest.DataMod.SemClient.ServerPort:='80';
    dm_apitest.DataMod.SemClient.ServerAddr:=urld.text;
    dm_apitest.DataMod.SemClient.Connect;
    dm_apitest.DataMod.SemClient.Request.Agent := 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.78 Safari/532.5';
    dm_apitest.DataMod.SemRequest.Request.Host:=urld.Text;
    dm_apitest.DataMod.SemRequest.Request.Query.Text:=URLText.Text;
    dm_apitest.DataMod.SemRequest.Request.Method:='GET';
    dm_apitest.DataMod.SemRequest.Post;

I am tring to get main form access to the events now - 'beginrequest' and 'datareceived' - fine if the controls are on the main form, which they have been up until now - but taking your origianl advice, I now need to clean things up and get the HTTP stuff onto the datamodules to join with the DB stuff.

I tried this in the DM:

   private
    { Private declarations }
   FOnDataReceived : TNotifyEvent;
   FOnBeginRequest : TNotifyEvent;
   public
     { Public declarations }
   property OnDataReceived : TNotifyEvent read FOnDataReceived write FOnDataReceived;
   property OnBeginRequest : TNotifyEvent read FOnBeginRequest write FOnBeginRequest;
   end;

and set up event readers in the main form by creating the notifiers with corresponding procedutres thus:

procedure TForm1.FormCreate(Sender: TObject);
begin
dm_apitest.DataMod.OnDataReceived := SemDataGet;
dm_apitest.DataMod.OnBeginRequest := SemBegin;
end;

& this at the end of the type/interface

    procedure SemDataGet(Sender : TObject);
    procedure SemBegin (Sender :TObject);

calling the procedures this way

procedure TForm1.SemBegin(Sender: TObject);
begin
TRtcDataClient(Sender).WriteHeader;
end;

procedure TForm1.SemDataGet(Sender: TObject);
var
ss : string;
begin
  if TRtcDataClient(Sender).Response.Started then
  begin
 //
  end;

if TRtcDataClient(Sender).Response.Done then
  begin

  some code here ...


  end;
end;

But as you can see, I have made a pig's ear of it all and my thinking has become muddled. Can you please advise how to employ the DM RTCCLients' events from the main form?

J

Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: April 24, 2012, 07:09:54 PM »

1. Move only RTC components to a DataModule if their events can be implemented inside the DataModule. But if some events on RTC components need access to other Forms, DataModules or components not available on the DataModule, then there is no advantage of moving them to a separate DataModule, since the move would only complicate things for you.

1. Do NOT try to create events for RTC components by hand. The same way you do it on a Form, you can create events for all components on a DataModule, simply by selecting the component and double-clicking the event in the Object inspector.

3. In your example code, you are accessing the "Request.Agent" property directly on the TRtcHttpClient component (SemClient). This is wrong. All request parameters should be set through the component used for handling the request/response (SemRequest in your case).

Best Regards,
Danijel Tkalcec
Logged
jonb2
Newbie
*
Posts: 36


« Reply #2 on: April 24, 2012, 07:25:05 PM »

Thanks for the speed of reply D.

1) Yup, I think I was beginning to realise this. All events should be self-contained on the DM. It's a relief to know this actually, I was trying to be too clever. One thing though, is there an easy way to notify the main form that an event has completed it's instructions ?

2) I won't

3) I will :-)

Thanks again Danijel, truly grateful, sometimes I need a brain reset, and your're good at that.

Cheers

Jon
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #3 on: April 24, 2012, 07:44:59 PM »

1. Here are a few ways to handle this:

A) If a DataModule will ONLY be used by a single Form, the easiest way is obviously to allow the DataModule to access the Form directly, for example by "using" the Form unit inside the "Implementation" section of the DataModule unit. Using another unit from the "implementation" section instead of the "interface" section avoids "circular unit reference" problems.

B) If you have several instances of the same TForm class, with one instances of a TDataModule class per Form, you could also use a public TForm property on the TDataModule class to pass the TForm instance to the TDataModule instance after creating them both, providing a link between them. This would avoid the need for a single global TForm instance, making it possible to use have several instances of the same TDataModule class, and use each of them from another instance of a TForm class.

C) If components on each DataModule will be used by only one Form, you could also declare events on a DataModule like you did in your 1st example, then map them to the event handlers you implement on the Form, and call them from within RTC events on the DataModule. In that case, there is no need to "use" the Form unit from the DataModule unit, so the link is more "loose". But the manual creation of events on the DataModule and manual mapping of events on the DataModule to event handlers on the Form makes it more complicated.

D) If the same components on a DataModule will be used by different Forms, and you want to be able to notify this-or-that object on this-or-that Form, you can use the "Request.Info.Obj[]" property when preparing the Request, through which you will make the object accessible from RTC events. And then, from inside the events, you can check if the object is set, cast it to your expected type and use it from the event code inside the DataModule.

Best Regards,
Danijel Tkalcec
Logged
jonb2
Newbie
*
Posts: 36


« Reply #4 on: April 24, 2012, 08:14:52 PM »

OK, I think I understand part of it.

1) If I get what you are meaning, it seems a good idea to create a third interface unit to 'join' the two forms together.

2) Here i am lost, of course i have found the 'info' property,

========== this on the main form after the post command

dm_apitest.DataMod.SemRequest.Request.Info[WHAT]

==== to this on the DM

procedure TDataMod.SemRequestBeginRequest(Sender: TRtcConnection);
begin
TRtcDataClient(Sender).WriteHeader;

WHERE?
end;

procedure TDataMod.SemRequestDataReceived(Sender: TRtcConnection);
begin

 if TRtcDataClient(Sender).Response.Started then
  begin
 // form1.Memo1.Clear;
  end;

if TRtcDataClient(Sender).Response.Done then
  begin

SemRushGet(Utf8Decode(TRtcDataClient(Sender).Read));

WHERE ??

  end;
end;

=====================

but how do i use it ?

What do i pass ? Please can I push my luck and you give me an example by filling in the gaps above

Sorry D, I need pictures again.

J
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #5 on: April 24, 2012, 08:44:21 PM »

Provided the object you want to pass on to the events on the DataModule is "MyForm" of type TMyForm ...

*Before* calling the Post method (and NOT afterwards), assign the MyForm object to the event, using something like:

dm_apitest.DataMod.SemRequest.Request.Info.Obj['The_Form']:=MyForm;

Naturally, you can also pass the "self" instance instead of "MyForm" variable, when you are inside an event of MyForm.

And then, from any RTC event triggered while processing the request/response chain, you can access that Form object like ...

var ThisIsMyForm:TMyForm;
begin
...
// To access the Form object stored in the Request.Info.Obj['The_Form'] parameter,
// you should assign it to a local variable like ...

ThisIsMyForm:=TMyForm( TRtcDataClient(Sender).Request.Info.Obj['The_Form'] );

// From here on, you can access the "TMyForm" object through the "ThisIsMyForm" local variable.
...
end;

Best Regards,
Danijel Tkalcec
Logged
jonb2
Newbie
*
Posts: 36


« Reply #6 on: April 24, 2012, 08:57:49 PM »

OK D. I think I have it. I am going to leave it until the morning now. Fresher eyes and mind.

A huge danke schoen as always.
Logged
jonb2
Newbie
*
Posts: 36


« Reply #7 on: April 25, 2012, 10:21:22 AM »

Morning Danijel

Nope. Out with the butterflies this morning.

Here is what I want to do:

============ 'GET' call form the main form

procedure TForm1.btnSemGetClick(Sender: TObject);
var
urlget: string;
MyDM : TDataMod;

begin
    //APIno:=1;
    //urld.SelectAll;
    //urlget:=urld.Text;
    dm_apitest.DataMod.SemClient.ServerPort:='80';
    dm_apitest.DataMod.SemClient.ServerAddr:=urld.text;
    dm_apitest.DataMod.SemClient.Connect;
    dm_apitest.DataMod.SemClient.Request.Agent := 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.78 Safari/532.5';


    dm_apitest.DataMod.SemRequest.Request.Host:=urld.Text;
   // urltext.SelectAll;
    dm_apitest.DataMod.SemRequest.Request.Query.Text:=URLText.Text;
    dm_apitest.DataMod.SemRequest.Request.Method:='GET';
    dm_apitest.DataMod.SemRequest.Request.Info.Obj['DMForm']:=dm_apitest.DataMod;
    MyDM:=TDataMod(DataMod.SemRequest.Request.Info.Obj['DMForm']);

    dm_apitest.DataMod.SemRequest.Post;


   if MyDM.SemRequest.OnDataReceived is done then  <<  I just want a simple notification that this event has happened

          ... do something

  end;

=================

So on an event such as this:

procedure TDataMod.SemRequestBeginRequest(Sender: TRtcConnection);
begin
TRtcDataClient(Sender).WriteHeader;
end;

==

1) I understand that the datarequest (SemRequest) has an event call BeginRequest. and

2) there is a property called TRtcConnection and another property TRTCDataClient to write the header ..... but how are these two accessible from the main form

I am thinking that putting the clients on the datamodules is far more trouble than it is worth.

Apologies for my denseness.

J
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #8 on: April 25, 2012, 01:07:28 PM »

This is wrong:
   dm_apitest.DataMod.SemClient.Request.Agent := 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.78 Safari/532.5';
It should be ...
    dm_apitest.DataMod.SemRequest.Request.Agent := 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.78 Safari/532.5';

This makes absolutely no sense:
   dm_apitest.DataMod.SemRequest.Request.Info.Obj['DMForm']:=dm_apitest.DataMod;
    MyDM:=TDataMod(DataMod.SemRequest.Request.Info.Obj['DMForm']);

What I meant is that you could store the FORM object inside "Request.Info.Obj[]", so it can be accessed from TRtcDataRequest events, even if the TRtcDataRequest component is NOT placed on the Form. But looking at your code now, that wasn't your goal.

About your question ...
1) I understand that the datarequest (SemRequest) has an event call BeginRequest. and

2) there is a property called TRtcConnection and another property TRTCDataClient to write the header ..... but how are these two accessible from the main form?

Read, Write and WriteHeader methods should ONLY be used from the context of RTC events (triggered on components responsible for request/response processing). Would you want to use Read, Write or WriteHeader methods from any other procedure or method, you would need to call that other procedure or method from inside RTC events responsible for request/response processing (like OnBeginRequest, OnDataReceived, OnDataSent).

I am thinking that putting the clients on the datamodules is far more trouble than it is worth.

Putting "clients" (TRtcHttpClient component) on the DataModule is NOT a problem. But, you are trying to put a TRtcDataRequest component on a DataModule, even though you want to keep the control of that component on the Form. And that is (obviously) not worth the trouble.

The only thing you could do, is place the TRtcHttpClient component ("SemClient" in your case) on the Main Form or the main DataModule, so it will be created before anything else, and made accessible to all the other components which need it (TRtcDataRequest and TRtcClientModule).

As for the TRtcDataRequest components... because you can have as many TRtcDataRequest components as you want, even if all of them will be using a single TRtcHttpClient component, there is no reason for placing a TRtcDataRequest component on a DataModule when you ONLY want to use it from a Form.

To make a long story short, keep it simple. And in your case, it means keeping the TRtcDataRequest component on the Form. If you need to process requests on other Forms or DataModules, just drop a new TRtcDataRequest component there and link its "Client" property to your main TRtcHttpClient component.

Best Regards,
Danijel Tkalcec
Logged
jonb2
Newbie
*
Posts: 36


« Reply #9 on: April 25, 2012, 01:22:48 PM »

D, that's cleared up my (in)decision.

All RTC components will go on the main form. Only after-request string processing and DB IO stuff will go on the datamodules.

So not to be boring, as I have to say it again, but in another language. Merci encore.

Jon



Logged
jonb2
Newbie
*
Posts: 36


« Reply #10 on: April 25, 2012, 01:45:15 PM »

D. Sorry, missed the part about splitting the client and request - implemented, gracias, works perfectly. Makes me feel really silly it could be so simple.

If you were here, I would buy you the largest and most expensive pint I could find  Smiley. But let's take a rain check on it, as there is plenty of that around too at the mo.

J
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #11 on: April 25, 2012, 01:48:40 PM »

Glad I could help.

Best Regards,
Danijel Tkalcec
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.031 seconds with 17 queries.