Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.

DECF4 and Delphi StyleManager

Post Reply
sboydlns
Posts: 7
Joined: Fri Jan 13, 2023 7:48 pm

DECF4 and Delphi StyleManager

Post 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
User avatar
salvadordf
Posts: 4057
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: DECF4 and Delphi StyleManager

Post 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.
sboydlns
Posts: 7
Joined: Fri Jan 13, 2023 7:48 pm

Re: DECF4 and Delphi StyleManager

Post 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
sboydlns
Posts: 7
Joined: Fri Jan 13, 2023 7:48 pm

Re: DECF4 and Delphi StyleManager

Post 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
dilfich
Posts: 330
Joined: Thu Nov 30, 2017 1:17 am

Re: DECF4 and Delphi StyleManager

Post 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.
User avatar
salvadordf
Posts: 4057
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: DECF4 and Delphi StyleManager

Post 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.
sboydlns
Posts: 7
Joined: Fri Jan 13, 2023 7:48 pm

Re: DECF4 and Delphi StyleManager

Post 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.
sboydlns
Posts: 7
Joined: Fri Jan 13, 2023 7:48 pm

Re: DECF4 and Delphi StyleManager

Post by sboydlns »

I think I finally have it working. I had to put Application.ProcessMessages after TrySetStyle.
Post Reply