Jump to content

Incus J

  • Content Count

  • Joined

  • Last visited

Community Reputation

3 Neutral

Technical Information

  • Delphi-Version
    Delphi 11 Alexandria

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Thanks Dave and Kas - some really neat approaches there - I will give them a try!
  2. Incus J

    Exec JS scripts in TEdgeBrowser

    I think that's actually quite a good solution! (Especially given what TEdgeBrowser provides for you to work with :) If I've understood it correctly it does mean that JSExec2 could complete before JSExec1 completes - if JSExec1 turns out to be the lengthier process. But it kind of gives synchronous behaviour in the end by waiting for all results to come in. Would just need to be careful to ensure script2 doesn't depend directly on the result of script1 (?) (since they might not complete in the order they were queued).
  3. I guess I could modify things so neither class initialises at startup. And have some separate custom startup routine that explicitly initialises each class in the order I desire. But to make that work I'd need to give each class a non-standard class initialisation method (i.e. not called Create) for me to call. Which seems a bit ugly. Definitely interested to hear David's thoughts!
  4. Oh - yes, thank you. Some time later: My head hurts. This line jumped out at me though: Based on what I've just read I think I might abandon trying to get TClassA to initialise before TClassB, and find another approach where it no longer matters which order the classes get initialised in. Yet somehow I've got to get that data storage path initialised before TClassB initialises - but since the path will be used by other classes too, I can't really do the obvious and get TClassB to initialise the path itself.
  5. Thanks - although that didn't work, it did get me thinking more closely about what is actually happening: TClassA is a Controller that uses TClassB (Model), so B probably gets class construction priority. However although TClassB is unaware of TClassA (as it currently stands unitA uses unitB, but unitB does not use unitA) TClassA initialises a data storage path elsewhere that TClassB happens to use. I sense a restructuring is required.
  6. Incus J

    Exec JS scripts in TEdgeBrowser

    ExecuteScript runs asynchronously I think - it returns (potentially) before the script has finished executing. There's a web page View Source example here, which looks similar to your setup, but the event has different parameters: https://blogs.embarcadero.com/execute-scripts-and-view-source-with-tedgebrowser/ uses System.NetEncoding; procedure TEdgeViewForm.EdgeBrowser1ExecuteScript(Sender: TCustomEdgeBrowser; AResult: HRESULT; const AResultObjectAsJson: string); begin if AResultObjectAsJson <> 'null' then memoHTML.Text := TNetEncoding.URL.Decode(AResultObjectAsJson).DeQuotedString('"'); end; The above code looks slightly odd at a glance, in that the event is named ExecuteScript too - perhaps it's a typo? A really messy way to wait, at least just as a quick test, might be: procedure TForm1.Button1Click(Sender: TObject); var LMyScript: String; begin FMyResult := ''; // Clear it LMyScript := 'window.chrome.webview.postMessage("MyResult");'; EdgeBrowser.ExecuteScript(LMyScript); //How wait for EdgeBrowserWebMessageReceived() to get FMyResult? while FMyResult = '' do Application.ProcessMessages; // Not good - but might work ShowMessage(FMyResult); end; Of course if the script fails to return a result, your app is left hanging - and Application.ProcessMessages would allow other events to trigger that you might not be anticipating - like the user clicking buttons in the UI. Assuming synchronous behaviour is desired, you could perhaps avoid Application.ProcessMessages altogether by moving ShowMessage(FMyResult); into the WebMessageReceived handler, and disable the UI while your function executes? Incidentally I've posted a feature request for an improved FMX TWebBrowser.EvaluateJavascript function that returns a result. I don't think FMX TWebBrowser currently surfaces an OnScriptExecutionCompleted event: https://quality.embarcadero.com/browse/RSP-35537 Since getting a result back from script execution is a very common use case, I think it would be great if VCL TEdgeBrowser and FMX TWebBrowser could be enhanced to include this sort of functionality built in (synchronous and asynchronous).
  7. I have two classes (TClassA and TClassB) declared in separate units. Both have a class constructor which executes automatically when the app starts: type TClassB=class(TObject) class constructor Create; ... class constructor TClassB.Create; begin //Some class initialization code end Note that this is a class constructor, not a regular instance constructor. At present, when the app starts up TClassB's class constructor runs first, and then TClassA's class constructor follows afterwards. In this particular case I want the opposite to occur - I want TClassA to run its class constructor code before TClassB runs its class constructor. How can I achieve that? (I've tried swapping the order of the unit declarations in the Project source .dpr file, but that had no effect)
  8. Incus J

    TWebBrowser Edge Engine Unavailable

    I think I've got it working by installing the Evergreen-Standalone version of WebView2. So it could simply be that the FMX TWebBrowser doesn't support the Fixed-Version of WebView2 currently.
  9. Incus J

    TWebBrowser Edge Engine Unavailable

    Thank you - I'm currently reading. Yes, I'm using Delphi's built in FMX TWebBrowser control - which has a WindowsEngine property to select the Edge engine at design time. I just haven't figured out how to get it to work at runtime. It is interesting that the VCL TEdgeBrowser control exposes the BrowserExecutableFolder property in the Object Inspector at design time. But FMX TWebBrowser does not. I wonder whether that is an intended or unintended omission?
  10. Incus J

    TWebBrowser Edge Engine Unavailable

    I think I'm slowly beginning to get a glimmer of understanding - it's slightly more complex than I anticipated. As well as the EdgeView2 SDK, I've also downloaded and expanded Microsoft's Fixed-Version-Runtime of WebView2, and placed the resulting folder(s) inside my app folder. So I think I now have all the ingredients. TWebBrowser will need to know where this Fixed-Version-Runtime folder is. How do I set a path to this in FMX TWebBrowser? There is the BrowserExecutableFolder property which I suspect is for this purpose. It is defined in the FMX.WebBrowser.Win unit: TEdgeBrowserHelper = class helper for TWinNativeWebBrowser ... property BrowserExecutableFolder: string read GetBrowserExecutableFolder write SetBrowserExecutableFolder; But I've yet to discover exactly how this helper attaches to TWebBrowser itself - BrowserExecutableFolder is not a property exposed in the Object Inspector. Presumably the private field FWeb references. Do I somehow need to cast my TWebBrowser instance to a TWinNativeWebBrowser at runtime in order to set this property? All of this seems private - the types are declared in the unit implementation section. I must be expected to access this some other way. How do I ensure the BrowserExecutableFolder property is set to the correct path prior to TWebBrowser attempting to initialise its view?
  11. Incus J

    TWebBrowser Edge Engine Unavailable

    No I hadn't - now installed, thank you! After dropping WebView2Loader.dll into the app folder, the error message has changed to "Failed to create instance of Edge browser engine" (The DLL file is version 1.0.664.37). That suggests the Edge engine is available though. It is failing here: procedure TWinNativeWebBrowser.InitializeWebView; begin ... // Create the environment var hr := CreateCoreWebView2EnvironmentWithOptions(PChar(BrowserExecutableFolder), PChar(UserDataFolder), nil, Callback<HResult, ICoreWebView2Environment>.CreateAs<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>( CreateEnvironmentCompleted)); if not ProcessHResult(hr) then begin FBrowserControlState := TBrowserControlState.Failed; DoCreateWebViewCompleted(False); end; end; BrowserExecutableFolder and UserDataFolder both appear to be empty - so I need to check whether that is significant. ProcessHResult(hr) is returning False for a hr value of -2147024894.
  12. When I drag and drop new controls from the Palette onto an FMX Form, I'm finding the control tends to be created some way off the right and bottom edge of the form. In other words the new control does not appear anywhere near the location of my mouse cursor. I can correct it by typing coordinates into the Position property in the Object Inspector. Is anyone else experiencing this, or is it a quirk of my setup? My system is High-DPI.
  13. Incus J

    TWebBrowser Edge Engine Unavailable

    I'm unsure how to get FMX TWebBrowser to use the Edge engine instead of the older IE engine. I've set its WindowsEngine property to EdgeOnly (Delphi 11). But I'm seeing a runtime error "Edge browser engine unavailable". Edge is installed. I think in the past a .dll file was required (?) I'm not sure whether this is still the case. After a Google search I looked in Delphi's Redist folder - but can't see anything that looks promising there. (On a vaguely related note - is there a way to z-order web controls in FMX? I'd like to place some controls so that they partially overlap TWebBrowser - appear on top of the web content - but they get clipped.)
  14. Incus J

    Choose a Folder dialog

    FMX.Dialogs function SelectDirectory(const Caption: string; const Root: string; var Directory: string): Boolean; Thank you f.m - that's exactly what I'm looking for!
  15. Incus J

    Choose a Folder dialog

    Thank you Remy, Wil, f.m, The code I found online is the same fmxexpress example Wil mentions above, so I've been playing around with it. If I comment out the following block, then it works without crashing the app: if ADir <> '' then begin LInitialDir := TNSURL.Create; LInitialDir.initFileURLWithPath(NSSTR(ADir)); LOpenDir.setDirectoryURL(LInitialDir); end; The crash was occurring on LInitialDir.initFileURLWithPath(NSSTR(ADir)); and when I stepped through the code ADir appeared to be '' empty, so I'm not sure how this block was executing at all. I guess without this block I'm losing the capability for specifying an initial starting folder. I also get a warning that NSSTR is deprecated, but the suggested replacement StrToNSStr is not recognised. Is there an easy way to query which system unit a function might be in?