Je suis débutant en Delphi. J'utilise actuellement la version Berlin de Delphi.
J'essaie d'invoquer une fonction/méthode Delphi à partir de JavaScript. Par exemple, je veux ouvrir un nouveau formulaire Delphi en cliquant sur le bouton html avec un attribut de données supplémentaires.
CODE HTML
<input type="button" name="btn" value="Button" id="edit" data-prop="24"></button>
<input type="button" name="btnAnother" value="Button2" id="edit2" data-prop="1"></button>
Lorsque l'on clique sur le bouton, un nouveau [deuxième formulaire] Delphi s'ouvre et affiche les éléments suivants données-propreté de bouton sur un TLabel.
[MISE À JOUR - 12-10-2020]
J'ai essayé de créer une application avec l'aide de la démo de JSExtension. J'ai essayé d'ajouter un événement de clic en javascript mais l'événement de clic sur le html ne se déclenche pas et le deuxième formulaire ne se charge pas. Voici une partie du code
HTML [jsExtensionClickEvent.html]
<!DOCTYPE html>
<html>
<body>
<form method="POST">
<input type="button" name="btnEx" value="Button" id="edit" data-prop="1"></button>
<input type="button" name="anotherBtn" value="Another Button" id="edit2" data-prop="24"></button>
</form>
</body>
</html>
DELPHI
Classe du gestionnaire d'extension [uExtensionHandler.pas].
unit uExtensionHandler;
{$I cef.inc}
interface
uses
{$IFDEF DELPHI16_UP}
Winapi.Windows,
{$ELSE}
Windows,
{$ENDIF}
uCEFRenderProcessHandler, uCEFBrowserProcessHandler, uCEFInterfaces,
uCEFProcessMessage,
uCEFv8Context, uCEFTypes, uCEFv8Handler;
const
MOUSECLICK_MESSAGE_NAME = 'mouseclick';
type
TExtensionHelper = class(TCefv8HandlerOwn)
protected
function Execute(const name: ustring; const object_: ICefv8Value;
const arguments: TCefv8ValueArray; var retval: ICefv8Value;
var exception: ustring): Boolean; override;
end;
implementation
{ TExtensionHelper }
function TExtensionHelper.Execute(const name: ustring;
const object_: ICefv8Value; const arguments: TCefv8ValueArray;
var retval: ICefv8Value; var exception: ustring): Boolean;
var
TempMessage: ICefProcessMessage;
TempFrame: ICefFrame;
begin
Result := False;
try
if (name = 'mouseclick') then
begin
if (length(arguments) > 1) and arguments[0].IsString and arguments[1].IsString
then
begin
TempMessage := TCefProcessMessageRef.New(arguments[1].GetStringValue);
TempMessage.ArgumentList.SetString(0, arguments[0].GetStringValue);
TempFrame := TCefv8ContextRef.Current.Browser.MainFrame;
if (TempFrame <> nil) and TempFrame.IsValid then
TempFrame.SendProcessMessage(PID_BROWSER, TempMessage);
end;
Result := True;
end;
finally
TempMessage := nil;
end;
end;
end.
Formulaire principal [uMainForm.pas]
unit uMainForm;
interface
uses
{$IFDEF DELPHI16_UP}
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
Vcl.ComCtrls, System.IOUtils,
{$ELSE}
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, IOUtils,
{$ENDIF}
uCEFChromium, uCEFWindowParent, uCEFInterfaces, uCEFApplication, uCEFTypes,
uCEFConstants,
uCEFWinControl, uCEFSentinel, uCEFChromiumCore;
const
MINIBROWSER_SHOWSECONDFORM = WM_APP + $100;
type
TForm1 = class(TForm)
CEFWindowParent1: TCEFWindowParent;
Chromium1: TChromium;
Timer1: TTimer;
procedure FormShow(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Timer1Timer(Sender: TObject);
procedure Chromium1ProcessMessageReceived(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame;
sourceProcess: TCefProcessId; const message: ICefProcessMessage;
out Result: Boolean);
procedure Chromium1AfterCreated(Sender: TObject;
const browser: ICefBrowser);
procedure Chromium1BeforePopup(Sender: TObject; const browser: ICefBrowser;
const frame: ICefFrame; const targetUrl, targetFrameName: ustring;
targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean;
const popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo;
var client: ICefClient; var settings: TCefBrowserSettings;
var extra_info: ICefDictionaryValue;
var noJavascriptAccess, Result: Boolean);
procedure Chromium1Close(Sender: TObject; const browser: ICefBrowser;
var aAction: TCefCloseBrowserAction);
procedure Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
procedure Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
const frame: ICefFrame; httpStatusCode: Integer);
private
{ Private declarations }
public
{ Public declarations }
protected
Fid: string;
// Variables to control when can we destroy the form safely
FCanClose: Boolean; // Set to True in TChromium.OnBeforeClose
FClosing: Boolean; // Set to True in the CloseQuery event.
procedure BrowserCreatedMsg(var aMessage: TMessage);
message CEF_AFTERCREATED;
procedure BrowserDestroyMsg(var aMessage: TMessage); message CEF_DESTROY;
procedure ShowSecondForm(var aMessage: TMessage);
message MINIBROWSER_SHOWSECONDFORM;
procedure WMMove(var aMessage: TWMMove); message WM_MOVE;
procedure WMMoving(var aMessage: TMessage); message WM_MOVING;
procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP;
procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP;
end;
var
Form1: TForm1;
procedure CreateGlobalCEFApp;
implementation
uses
uSecondForm, uCEFMiscFunctions, uCEFDictionaryValue, uExtensionHandler;
procedure GlobalCEFApp_OnWebKitInitialized;
var
TempExtensionCode: string;
TempHandler: ICefv8Handler;
begin
try
TempExtensionCode := 'var myextension;' + 'if (!myextension)' +
' myextension = {};' + '(function() {' +
' myextension.mouseclick = function(b,c) {' +
' native function mouseclick();' + ' mouseclick(b,c);' + ' };'
+ '})();';
TempHandler := TExtensionHelper.Create;
if CefRegisterExtension('myextension', TempExtensionCode, TempHandler) then
{$IFDEF DEBUG}CefDebugLog('JavaScript extension registered successfully!'){$ENDIF}
else
{$IFDEF DEBUG}CefDebugLog('There was an error registering the JavaScript extension!'){$ENDIF};
finally
TempHandler := nil;
end;
end;
procedure CreateGlobalCEFApp;
begin
GlobalCEFApp := TCefApplication.Create;
GlobalCEFApp.OnWebKitInitialized := GlobalCEFApp_OnWebKitInitialized;
{$IFDEF DEBUG}
GlobalCEFApp.LogFile := 'debug.log';
GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO;
{$ENDIF}
end;
{$R *.dfm}
{ TForm1 }
procedure TForm1.BrowserCreatedMsg(var aMessage: TMessage);
begin
CEFWindowParent1.UpdateSize;
end;
procedure TForm1.BrowserDestroyMsg(var aMessage: TMessage);
begin
CEFWindowParent1.Free;
end;
procedure TForm1.Chromium1AfterCreated(Sender: TObject;
const browser: ICefBrowser);
begin
PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
end;
procedure TForm1.Chromium1BeforeClose(Sender: TObject;
const browser: ICefBrowser);
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
procedure TForm1.Chromium1BeforePopup(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame;
const targetUrl, targetFrameName: ustring;
targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean;
const popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo;
var client: ICefClient; var settings: TCefBrowserSettings;
var extra_info: ICefDictionaryValue; var noJavascriptAccess, Result: Boolean);
begin
Result := (targetDisposition in [WOD_NEW_FOREGROUND_TAB,
WOD_NEW_BACKGROUND_TAB, WOD_NEW_POPUP, WOD_NEW_WINDOW]);
end;
procedure TForm1.Chromium1Close(Sender: TObject; const browser: ICefBrowser;
var aAction: TCefCloseBrowserAction);
begin
PostMessage(Handle, CEF_DESTROY, 0, 0);
aAction := cbaDelay;
end;
procedure TForm1.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
const frame: ICefFrame; httpStatusCode: Integer);
var
TempJSCode: string;
begin
Chromium1.LoadURL('file:///jsExtensionClickEvent.html');
TempJSCode := 'document.body.addEventListener("click", function (evt) { ' +
' function getpath(n) {' +
' var result = document.getElementById(n.id).getAttribute("data-prop"); ' +
' return result; ' + ' } '
+' myextension.mouseclick(getpath(evt.target), ' +
quotedstr(MOUSECLICK_MESSAGE_NAME) + ');});';
frame.ExecuteJavaScript(TempJSCode, 'about:blank', 0);
end;
procedure TForm1.Chromium1ProcessMessageReceived(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame;
sourceProcess: TCefProcessId; const message: ICefProcessMessage;
out Result: Boolean);
begin
Result := False;
if (message = nil) or (message.ArgumentList = nil) then
exit;
// This function receives the messages with the JavaScript results
if (message.Name = MOUSECLICK_MESSAGE_NAME) then
begin
Fid := message.ArgumentList.GetString(0);
PostMessage(Handle, MINIBROWSER_SHOWSECONDFORM, 0, 0);
// this doesn't create/destroy components
Result := True;
end;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := FCanClose;
if not(FClosing) then
begin
FClosing := True;
Visible := False;
Chromium1.CloseBrowser(True);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FCanClose := False;
FClosing := False;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
// GlobalCEFApp.GlobalContextInitialized has to be TRUE before creating any browser
// If it's not initialized yet, we use a simple timer to create the browser later.
if not(Chromium1.CreateBrowser(CEFWindowParent1, '')) then
Timer1.Enabled := True;
end;
procedure TForm1.ShowSecondForm(var aMessage: TMessage);
begin
Form2.Label1.Caption := Fid;
Form2.ShowModal;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
if not(Chromium1.CreateBrowser(CEFWindowParent1, '')) and
not(Chromium1.Initialized) then
Timer1.Enabled := True;
end;
procedure TForm1.WMEnterMenuLoop(var aMessage: TMessage);
begin
inherited;
if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then
GlobalCEFApp.OsmodalLoop := True;
end;
procedure TForm1.WMExitMenuLoop(var aMessage: TMessage);
begin
inherited;
if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then
GlobalCEFApp.OsmodalLoop := False;
end;
procedure TForm1.WMMove(var aMessage: TWMMove);
begin
inherited;
if (Chromium1 <> nil) then
Chromium1.NotifyMoveOrResizeStarted;
end;
procedure TForm1.WMMoving(var aMessage: TMessage);
begin
inherited;
if (Chromium1 <> nil) then
Chromium1.NotifyMoveOrResizeStarted;
end;
end.
Deuxième formulaire [uSecondForm.pas]
unit uSecondForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm2 = class(TForm)
Label1: TLabel;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
end.
Contenu du fichier journal
[1012/202103.335:ERROR:CEF4Delphi(1)] PID: 6708, TID: 2872, PT: Renderer - JavaScript extension registered successfully!
[1012/203832.621:ERROR:CEF4Delphi(1)] PID: 6660, TID: 6748, PT: Renderer - JavaScript extension registered successfully!
[1012/203832.688:ERROR:CEF4Delphi(1)] PID: 5436, TID: 6016, PT: Renderer - JavaScript extension registered successfully!
En cliquant sur le bouton, vous obtenez le journal des événements de débogage ci-dessous. Cef4DelphiJsExtension.exe est le nom de l'application.
Thread Start: Thread ID: 1732. Process Cef4DelphiJsExtension.exe (7156)
Thread Exit: Thread ID: 1732. Process Cef4DelphiJsExtension.exe (7156)
Thread Start: Thread ID: 1180. Process Cef4DelphiJsExtension.exe (7156)
Thread Exit: Thread ID: 2076. Process Cef4DelphiJsExtension.exe (7156)
Thread Exit: Thread ID: 6592. Process Cef4DelphiJsExtension.exe (7156)
Thread Start: Thread ID: 7200. Process Cef4DelphiJsExtension.exe (7156)
Thread Start: Thread ID: 7220. Process Cef4DelphiJsExtension.exe (7156)
Thread Start: Thread ID: 7276. Process Cef4DelphiJsExtension.exe (7156)
Thread Exit: Thread ID: 7276. Process Cef4DelphiJsExtension.exe (7156)
Thread Start: Thread ID: 7376. Process Cef4DelphiJsExtension.exe (7156)
Thread Exit: Thread ID: 7376. Process Cef4DelphiJsExtension.exe (7156)
Thread Exit: Thread ID: 7220. Process Cef4DelphiJsExtension.exe (7156)
Merci.