Page 1 of 1

DECF4 and Delphi StyleManager

Posted: Wed Jan 18, 2023 5:57 pm
by sboydlns
Setting a style other than the Windows default using TSyleManager.TrySetStyle (I am using Delphi XE2) causes web pages to no longer display in TCEFWindowParent. Does anyone know why this is and what I can do to fix it?

Thanks in advance

Steve

Re: DECF4 and Delphi StyleManager

Posted: Thu Jan 19, 2023 7:35 am
by salvadordf
Selecting a new VCL style at runtime recreates the control handles. When Chromium detects that the handles are destroyed it thinks that the application is closing and the browser should be destroyed too.

We have 2 workarounds :
  • Set the style when the app is starting and warn the user that any style change requires an application restart.
  • Close all the browsers before the application sets a new style at runtime and open the browsers manually after that if necessary.

Re: DECF4 and Delphi StyleManager

Posted: Thu Jan 19, 2023 3:10 pm
by sboydlns
Moving the code to set the style at program start up to a point before the browsers are created seems to fix the biggest problem. I'll keep hacking away at the case where the style is changed while the program is active.

Thanks
Steve

Re: DECF4 and Delphi StyleManager

Posted: Fri Jan 20, 2023 4:59 pm
by sboydlns
Now I am trying to solve the problem of the web page not displaying in the CEFWindowParent when the style is changed while the window is active.

Here is what I am doing:

Chromium.CloseAllBrowsers;
TStyleManager.TrySetStyle(newStyle);
Chromium.CreateBrowser(CEFWindowParent);
Chromium.LoadUrl(url);

Sometimes this causes the program to close with no error shown. Sometimes the web page simply doesn't appear in CEFWindowParent.

Tracing through LoadUrl shows Chromium.Initialized to be False, which causes the navigation to be skipped.

Steve

Re: DECF4 and Delphi StyleManager

Posted: Sat Jan 21, 2023 6:42 am
by dilfich
Create and recreate the browser yourself, much like TinyBrowser.

Something like this..

Code: Select all

   TStyleManager.AnimationOnControls:= True;
   TStyleManager.TrySetStyle(SName, false);

   if Assigned(CefWindowParent[0]) then FreeAndNil(CefWindowParent[0]);
   if Assigned(ChromeCEF[0]) then FreeAndNil(ChromeCEF[0]);
+++

CreateСEF;

Code: Select all

  if Assigned(ChromeCEF[0]) then FreeAndNil(ChromeCEF[0]);
  ChromeCEF[0]:= TChromModCEF.Create(nil);

  if Assigned(CefWindowParent[0]) then FreeAndNil(CefWindowParent[0]);
  CefWindowParent[0]:= TCEFWindowParent.Create(nil);
  CefWindowParent[0].Parent:= Form1.PanBR1;
...... ALL PARAM
ChromeCEF[0].Chromium.CreateBrowser(CefWindowParent[0], '', BRContext[0]);
Creating a browser at startup, when changing the style, the browser must create a new one.

Re: DECF4 and Delphi StyleManager

Posted: Sat Jan 21, 2023 9:41 am
by salvadordf
sboydlns wrote: Fri Jan 20, 2023 4:59 pm Here is what I am doing:
Chromium.CloseAllBrowsers;
TStyleManager.TrySetStyle(newStyle);
Chromium.CreateBrowser(CEFWindowParent);
Chromium.LoadUrl(url);
The browser destruction is asynchronous. It takes several steps that are described in the code comments of each demo.
This means that it's not possible to close the browsers and immediately create new ones.

Re: DECF4 and Delphi StyleManager

Posted: Sun Jan 22, 2023 5:23 pm
by sboydlns
I have tried this several different ways and I still can't make it work.

I added the rather convoluted code required to safely destroy the browser in TChromium.OnClose and TChromium.OnBeforeClose. Like this:

Code: Select all

procedure TMenu5Form.browseWindowBeforeClose(Sender: TObject; const browser: ICefBrowser);
begin
    // The main browser is being destroyed
    if ((browseWindow.BrowserId = 0) and FMainFormClosing) then
    begin
        FCanClose := True;
        PostMessage(Handle, WM_CLOSE, 0, 0);
    end;
end;

procedure TMenu5Form.browseWindowClose(Sender: TObject; const browser: ICefBrowser;
  var aAction: TCefCloseBrowserAction);
begin
    if ((browser <> nil) and
        (browseWindow.BrowserId = browser.Identifier) and
        (CEFWindowParent <> nil)) then
    begin
        PostMessage(Handle, CEF_DESTROY, 0, 0);
        aAction := cbaDelay;
    end;
end;

procedure TMenu5Form.BrowserDestroyMsg(var aMessage: TMessage);
// Fire when a browser is being destroyed. Freeing CEFParentWindow here causes
// the browser.OnBeforeClose event to fire, which allows the program to finish
// closing.
begin
    FreeAndNil(CEFWindowParent);
end;

In the case where I am changing the style, FMainFormClosing will be False. This works fine when I close the main form.

When changing the style I do this:

Code: Select all

            // Destroy the browser and wait for all events to be processed.
            browseWindow.CloseAllBrowsers;
            while (browseWindow.BrowserId <> 0) do
            begin
                Sleep(10);
                Application.ProcessMessages;
            end;
            // Set the new style
            TStyleManager.TrySetStyle(Menu5Data.UserInfo.U_STYLE);
            fcurrentStyle := Menu5Data.UserInfo.U_STYLE;
            // Create a new browser
            CEFWindowParent := TCEFWindowParent.Create(Self);
            with CEFWindowParent do
            begin
                Parent := pnlBrowse;
                Align := alClient;
            end;
            FBrowserCreated := False;
            if (not browseWindow.CreateBrowser(CEFWindowParent)) then
                ShowMessage('OOPS!');
            while (not FBrowserCreated) do
            begin
                Sleep(10);
                Application.ProcessMessages;
            end;
            //
            browseWindow.LoadUrl(url);
FBrowserCreated is set to True in the TChromium.OnAfterCreated event.

Everything seems to proceed as I would expect until CreateBrowser is called. At this time, the AfterCreated event fires, then the OnBeforeClose event fires. Then when I try to use LoadUrl it fails because BrowserID = 0.

Re: DECF4 and Delphi StyleManager

Posted: Sun Jan 22, 2023 7:35 pm
by sboydlns
I think I finally have it working. I had to put Application.ProcessMessages after TrySetStyle.