Search code examples
firemonkeychromium-embeddeddelphicef4delphi

Using CEF4Delphi to show web page from firemonkey


I'm using Delphi 10.2 Tokyo and I installed CEF4Delphi because i think plain TWebBrowser component seems a little down in terms of performance and features.

What my project that I working on is showing web page, and no need to show any URL address. So I only need to show Web page.

I found some VCL Application Demos including CEF4Delphi, those are using another TChromiumWindow or similar things to showing web page. And also the Demos has only one(AFAIK) FMX Application example with Off Screen Rendering to showing in TFMXBufferPanel.

I tried exact thing for just create the form from Demos, load the URL, and AddObject to main layout, but showing nothing but only orange screen from demo project, or showing Access Violation error. I probably don't know to read API documents properly, I couldn't find about it.

I search for all of things from google related with CEF4Delphi and FMX, but those are out-dated, from the era of DCEF3 or Delphi before FMX. I'm about to give up and using VCL if there's no solution.

My conclusion,

  1. Can I load web page from Firemonkey with using CEF4Delphi? Only need to do is Load the web page.

  2. If above question is possible, will I can also available for take snapshot of screen and print the web page to get the copy of it or save to pdf? I think these are can done with one or two lines of source code.

I'll post my work I tried. Apologize for some of the commented code, my boss tried for it.

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
  FMX.Controls.Presentation, FMX.StdCtrls, uFMXExternalPumpBrowser;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Layout1: TLayout;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  f: TFMXExternalPumpBrowserFrm;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Layout1.AddObject(f.Panel1);
end;

procedure TForm1.Button2Click(Sender: TObject);
//var
//  MainFrame: ICefFrame;
begin

f.Show;
  f.LoadURL('naver.com');
//  f.Panel1.InvalidatePanel;
//
//  f.chrmosr.Browser.MainFrame.LoadUrl('naver.com');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  f := TFMXExternalPumpBrowserFrm.Create(nil);
end;

end.

And this is for program execute code.

program fmxwebtes;

uses
  System.StartUpCopy,
  FMX.Forms,
  WinApi.Windows,
  uCEFApplication,
  Unit1 in 'Unit1.pas' {Form1},
  uFMXApplicationService in 'uFMXApplicationService.pas',
  uFMXExternalPumpBrowser in 'uFMXExternalPumpBrowser.pas' {FMXExternalPumpBrowserFrm};

{$R *.res}

{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
begin

GlobalCEFApp := TCefApplication.Create;

  if GlobalCEFApp.StartMainProcess then
    begin
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    end;

  GlobalCEFApp.Free;
end.

Solution

  • Yes. You can load, take snapshots and print web pages with CEF4Delphi using the FMX component but the demo uses the off-screen rendering mode (OSR) and an external message pump which means that it's one of the most complicated demos in CEF4Delphi.

    To load a web page use TFMXChromium.LoadURL. To print use TFMXChromium.Print or TFMXChromium.PrintToPDF. To take a snapshot use TFMXBufferPanel.SaveToFile or copy the bitmap in the TFMXBufferPanel.Buffer property.

    It's much easier to add a browser to your app if you use a VCL component.

    Edit : Your DPR is missing several properties needed to make the FMX component work. Take a look at the DPR file in the FMXExternalPumpBrowser demo and you'll see that you need to create the work scheduler and set these GlobalCEFApp properties. The GlobalCEFApp_OnScheduleMessagePumpWork procedure is defined in uFMXExternalPumpBrowser.pas

    GlobalFMXWorkScheduler := TFMXWorkScheduler.Create(nil);
    
    GlobalCEFApp                            := TCefApplication.Create;
    GlobalCEFApp.WindowlessRenderingEnabled := True;
    GlobalCEFApp.EnableHighDPISupport       := True;
    GlobalCEFApp.FlashEnabled               := False;
    GlobalCEFApp.ExternalMessagePump        := True;
    GlobalCEFApp.MultiThreadedMessageLoop   := False;
    GlobalCEFApp.OnScheduleMessagePumpWork  := GlobalCEFApp_OnScheduleMessagePumpWork;
    

    Edit 2 : All CEF components need to be initialized before loading a website. You can't load a URL right after creating the component but you can set the TFMXChromium.DefaultUrl property to load your URL as soon as it's initialized.