[Pas2js] Pas2JS-Widgets with LFM streaming

Sven Barth pascaldragon at googlemail.com
Sat Jul 27 12:53:27 CEST 2019


Am 27.07.2019 um 11:47 schrieb Michael Van Canneyt:
>
>>>> program tp2j;
>>>>
>>>> {$mode objfpc}
>>>>
>>>> uses
>>>>   Forms, FormLoader, Interfaces, Unit1;
>>>>
>>>> procedure DoInit(aData: TObject);
>>>> begin
>>>>   Application.Initialize;
>>>>   Application.CreateForm(TWForm1, WForm1);
>>>>   Application.Run;
>>>> end;
>>>>
>>>> begin
>>>>   LoadForms([TWForm1], @DoInit, Nil);
>>>> end.
>>>>
>>>> === code end ===
>>>
>>> I think you can avoid this change by checking the 'Run rtl when all 
>>> page resources are fully loaded' options when creating your project.
>>>
>>> This will change the script tag to
>>>   window.addEventListener("load", rtl.run);
>>> so the program only runs when all forms are actually loaded, 
>>> avoiding the
>>> need to wait for the load.
>>
>> Sadly this does not work. I don't even see the browser fetching the 
>> file... :'(
>
> Strange. Probably because it does not recognize the type so it refuses to
> load it automatically. 

That's what I assume as well.

> Maybe a <link> element is better ?

Nope, no difference. It seems injecting directly into the HTML or 
dynamic loading are the only possibilities if I want to use the LFM 
format as is.

>
>>
>> However what might be interesting (even for further functionality) 
>> might be to run the HTML page through a template processor (*cough* 
>> fptemplate *cough*) and replace some tag with the contents of all 
>> forms. Or something like that...
>
> I had the exact same thought when I wrote
>
> "The changes to the html could be implemented without too much effort 
> in the IDE package."
>
> :-)

;)

>
>>>> - add a script tag in front of the project's script tag in the HTML 
>>>> file:   <script src="unit1.lfm" type="application/x-lazarus-form" 
>>>> id="TWForm1.lfm"></script>
>>>> - play around with the form (add components (from the Pas2JS 
>>>> component tab only!), add events, etc.)
>>>> - before compiling make sure that the project *does not* contain a 
>>>> requirement of Pas2JS_Designer_Package (the IDE currently adds this 
>>>> when adding a component)
>>>> - make sure that the *.LFM files are at the same location as the 
>>>> *.JS file
>>>> - load your application in the browser -> you should now see your form
>>>>
>>>> A screenshot showing the resulting browser and the IDE is attached. :)
>>>
>>> Nice job :-)
>>
>> Yes. Though I'd really like to know how TMS dealt with the sizes. 
>> Currently the problem is when I do this on a 92 DPI Lazarus (my Win7 
>> at work) I get buttons and labels that are too small for their 
>> contents and on my HighDPI Win10 the button and label looks huge 
>> compared to the content... (obviously the widgets need to deal with 
>> the different sizes/take into account the design DPI, but the 
>> principal problem of WYSIWYG remains)
>
> This is the problem of VCL/LCL : an outdated concept of (fixed) layout.

Which brings me back to the question: how did TMS solve this? After all 
they're using the normal form designer as well...

>
>> It's the former my FormLoader unit is based on. But loading the 
>> content itself is not the problem (I've done that part already ;) ). 
>> My (conceptual) problem is that the code is usually synchronous. E.g. 
>> take the default main program:
>>
>  [snip]
>>
>> In the block marked with (*************) I'd essentially need to load 
>> the form's resource dynamically from the server (the loading itself 
>> isn't the problem) and then wait until all has been received. My 
>> knowledge in JS isn't as good yet as to know the correct approach for 
>> that, my gut tells me that something akin to "async/await" would be 
>> necessary here.
>
> You can't run await in the main loop so that would not work as you 
> want it. There are no shortcuts for async, it is something to live with.
>
> In essence, TApplication.CreateForm() will need to be async.
>
> so a
>
> TFormLoadedEvent = Procedure(Sender : TObject; aForm : TCustomForm) of 
> Object;
>
> Property Tapplication.OnFormLoaded : TFormLoadedEvent
>
> is needed, allowing you to check that the form is loaded.
>
> TApplication.Run then needs to wait till the main form is loaded before
> showing it.

But how can TApplication.Run wait when waiting in the main thread is 
frowned upon or not really working?

Though I just noticed that TApplication.Run looks like this:

=== code begin ===

procedure TApplication.Run;
begin
   { TODO: Add a background to the application }
   RegisterHandleEvents;
   LoadIcon;
   if (Assigned(FMainForm)) then
   begin
     FMainForm.Show;
   end;
end;

=== code end ===

So it might be useful to kick out the if-clause and only rely on 
asynchronous loading.

Of course for creating forms in another form one would need to call 
TApplication.CreateForm as well instead of calling TSomeForm.Create if 
one wants to use a form with a LFM. Then TApplication.CreateForm would 
need a callback parameter which would contain the code after the form 
was successfully instantiated...

Maybe I can cook something up with that...

Of course there is more trouble ahead if a form depends e.g. on a data 
module and thus the latter must be loaded before the former... Oh well, 
no one said that it would be easy...

Regards,
Sven


More information about the Pas2js mailing list