Lazarus fpCEF3 - Учебный проект 3 - веб-интерфейс для десктопного приложения

В третьем проекте мы откроем полноценную веб-страницу (локальную) с несложным веб-интерфейсом пользователя.
Мы запретим переход по ссылкам (смену URL-адреса) и новые объекты браузера (окна), организуем синхронизацию с веб-страницей.

Никаких привычных контролов и меню десктоп-приложения мы делать не будем, заменим их на веб-контролы, хотя вы можете при желании продублировать или разделить некоторые функции.

Я приготовил простую тестовую локальную веб-страницу для этого учебного проекта. При желании вы можете программно формировать и менять содержимое локального HTML-файла, перезагружая затем его в браузере (Browser.Reload).

Скачать HTML-страницу в zip-архиве (33 Kb)

Тестовый HTML-файл этого проекта, чтобы не было вопросов лицензирования, содержит 100% мой собственный код (включая JavaScript-модуль VcorpJS) и может содержать веб-аналоги:

и т.д. и т.п. - который вы можете заменить на любой код и веб-фреймворк, с которым работаете.

Ничего не мешает работать с веб-страницами существующих сайтов и веб-систем, оптимизированных для работы с вашими десктопными клиентами - у таких веб-страниц больше прав по сравнению с локальными. Лучше не отключать в компоненте TChromium средства безопасности.

У нас должно получиться примерно следующее:
Скриншоты проекта в IDE и работающего приложения project3.exe

Project3 - Веб-интерфейс для десктопного приложения Project3 - Запуск с веб-интерфейсом Project3 - Запуск. html5 player Project3 - Запуск. html5 player во всё окно

Для навигации по всем страницам этого раздела сайта используйте иконку меню или ссылку Навигация в строке навигации.

Для этого проекта нам понадобится подключение дополнительного модуля LCLProc (если версия Lazarus IDE 1.4.4) или модуля LazUTF8 (если версия Lazarus IDE 1.6.0 и выше) - для поиска подстрок функцией UTF8Pos() - чтобы определять, что нам сообщает JavaScript браузера.

Создадим одну форму (главную), в свойстве Constrains установим «MinHeight=480» и «MinWidth=640» (тестовая HTML-страница использует минимум 640х480 пикселей).

Разместим на форме единственный контрол-компонент TChromium, который растянем на всю форму:
Anchors: [akTop,akLeft,akRight,akBottom]

Сделаем обработку ошибки загрузки страницы в браузер «OnLoadError»

procedure TForm1.Chromium1LoadError(Sender: TObject;
    const Browser: ICefBrowser; const Frame: ICefFrame;
    errorCode: TCefErrorCode; const errorText, failedUrl: ustring);
var v: variant;
begin
  v:=errorCode; // Ошибка загружки веб-страницы
  ShowMessage('Ошибка загрузки страницы' + #13 + 'errorCode = ' + IntToStr(v) + ' ' +
    UTF8Encode(errorText + #13 + failedUrl) + #13 + 'Попробуйте ещё раз');
end;

Создадим обработчик события «OnConsoleMessage» для синхронизации с нашей активной веб-страницей (HTML-файлом).
Наша тестовая веб-страница раз в секунду проверяет связь с нашим приложением, поэтому при каждом событии от консоли необходимо заново устанавливать значение переменной 'window.lz_cef3=1;' через вызов ExecuteJavaScript()
Наша тестовая HTML-страница начинает вывод в консоль с момента готовности DOM (по событию документа «DOMContentLoaded»), поэтому некоторые веб-ресурсы, на которые ссылается страница, могут быть ещё не подгружены.
Работу браузерного JS-кода см. в файле project3.html (для простоты можно искать все вызовы console.log(...), файл в кодировке UTF-8).

procedure TForm1.Chromium1ConsoleMessage(Sender: TObject;
    const Browser: ICefBrowser; const message, Source: ustring; line: Integer;
    out Result: Boolean);
var Str: String;
begin
  Str:=UTF8Encode(message);
  if (UTF8Pos('!cef3_close',Str)=1) then Close; // Нажали кнопку «Выход»
  if (UTF8Pos('!cef3_focus',Str)=1) then Form1.Chromium1.SetFocus;
  Browser.MainFrame.ExecuteJavaScript( Utf8Decode('window.lz_cef3=1;'), 'about:blank', 0);
end;

Запретим смену URL-адреса (переход по ссылкам не будет работать), а так-же создание новых объектов браузера (отдельных окон).
Создадим константу MainUrl с постоянным адресом веб-страницы.

Примечание: все ресурсы с относительным адресом, на которые ссылается любая веб-страница (изображения, стили и т.д.), должны быть доступны относительно адреса самой веб-страницы, вне зависимости от местонахождения браузера или нашего десктопного приложения.

procedure TForm1.Chromium1BeforeBrowse(Sender: TObject;
    const browser: ICefBrowser; const frame: ICefFrame;
    const request: ICefRequest; isRedirect: Boolean; out Result: Boolean);
begin
  if (UTF8Encode(Frame.Url)<>MainUrl) then
    Result:=False else Result:=True; // Запрет смены адреса MainUrl
end;

procedure TForm1.Chromium1BeforePopup(Sender: TObject;
    const browser: ICefBrowser; const frame: ICefFrame; const targetUrl, targetFrameName: ustring;
    targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean;
    var popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo; var client: ICefClient;
    var settings: TCefBrowserSettings; var noJavascriptAccess: Boolean;
    out Result: Boolean);
begin
  Result:=True; // Запрет новых объектов браузера (окон)
end;

И наконец, отключим дефолтное контекстное меню «model.Clear» в обработчике события «OnBeforeContextMenu»
Несложно сделать собственное контекстное меню, хоть через JavaScript, хоть через Obiect Pascal, хоть совместно.

procedure TForm1.Chromium1BeforeContextMenu(Sender: TObject;
    const Browser: ICefBrowser; const Frame: ICefFrame;
    const params: ICefContextMenuParams; const model: ICefMenuModel);
begin
  model.Clear; // Очистка контекстного меню
end;

Скачать project3.html в zip-архиве (33 Kb) - для выполнения совместно с рассмотренным здесь project3 для Lazarus.

project3.html нужно положить в папку, путь к которой прописан в константе const MainUrl

project3.lpr

program project3;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, Unit1
  { you can add units after this };

{$R *.res}

begin
  RequireDerivedFormResource := True;
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Form1.Chromium1.Load(MainUrl);
  Application.Run;
end.

unit1.pas

unit Unit1;

interface

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  LazUTF8, cef3lcl, cef3types, cef3intf, cef3gui;

type

  { TForm1 }

  TForm1 = class(TForm)
    Chromium1: TChromium;
    procedure Chromium1BeforeBrowse(Sender: TObject;
      const browser: ICefBrowser; const frame: ICefFrame;
      const request: ICefRequest; isRedirect: Boolean; out Result: Boolean);
    procedure Chromium1BeforeContextMenu(Sender: TObject;
      const Browser: ICefBrowser; const Frame: ICefFrame;
      const params: ICefContextMenuParams; const model: ICefMenuModel);
    procedure Chromium1BeforePopup(Sender: TObject; const browser: ICefBrowser;
      const frame: ICefFrame; const targetUrl, targetFrameName: ustring;
      targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean;
      var popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo;
      var client: ICefClient; var settings: TCefBrowserSettings;
      var noJavascriptAccess: Boolean; out Result: Boolean);
    procedure Chromium1ConsoleMessage(Sender: TObject;
      const Browser: ICefBrowser; const message, Source: ustring;
      line: Integer; out Result: Boolean);
    procedure Chromium1LoadError(Sender: TObject;
      const Browser: ICefBrowser; const Frame: ICefFrame;
      errorCode: TCefErrorCode; const errorText, failedUrl: ustring);
  private
    { private declarations }
  public
    { public declarations }
  end;

const
  MainUrl = 'file://localhost/G:/Lazarus/.../project3.html';

var
  Form1: TForm1;

implementation

{$R *.lfm}

  { TForm1 }

procedure TForm1.Chromium1BeforeBrowse(Sender: TObject;
    const browser: ICefBrowser; const frame: ICefFrame;
    const request: ICefRequest; isRedirect: Boolean; out Result: Boolean);
begin
  if (UTF8Encode(Frame.Url)<>MainUrl) then
    Result:=False else Result:=True; // Запрет смены адреса MainUrl
end;

procedure TForm1.Chromium1BeforeContextMenu(Sender: TObject;
    const Browser: ICefBrowser; const Frame: ICefFrame;
    const params: ICefContextMenuParams; const model: ICefMenuModel);
begin
  model.Clear; // Очистка контекстного меню
end;

procedure TForm1.Chromium1BeforePopup(Sender: TObject;
    const browser: ICefBrowser; const frame: ICefFrame; const targetUrl, targetFrameName: ustring;
    targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean;
    var popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo; var client: ICefClient;
    var settings: TCefBrowserSettings; var noJavascriptAccess: Boolean;
    out Result: Boolean);
begin
  Result:=True; // Запрет новых объектов браузера (окон)
end;

procedure TForm1.Chromium1ConsoleMessage(Sender: TObject;
    const Browser: ICefBrowser; const message, Source: ustring; line: Integer;
    out Result: Boolean);
var Str: String;
begin
  Str:=UTF8Encode(message);
  if (UTF8Pos('!cef3_close',Str)=1) then Close; // Нажали кнопку «Выход»
  if (UTF8Pos('!cef3_focus',Str)=1) then Form1.Chromium1.SetFocus;
  Browser.MainFrame.ExecuteJavaScript( Utf8Decode('window.lz_cef3=1;'), 'about:blank', 0);
end;

procedure TForm1.Chromium1LoadError(Sender: TObject;
    const Browser: ICefBrowser; const Frame: ICefFrame;
    errorCode: TCefErrorCode; const errorText, failedUrl: ustring);
var v: variant;
begin
  v:=errorCode; // Ошибка загружки веб-страницы
  ShowMessage('Ошибка загрузки страницы' + #13 + 'errorCode = ' + IntToStr(v) + ' ' +
    UTF8Encode(errorText + #13 + failedUrl) + #13 + 'Попробуйте ещё раз');
end;

end.

  • «Lazarus fpCEF3» - Главная страница раздела
  • Учебные проекты
  • project1 - первый запуск
  • project2 - один объект (окно) и контекстное меню
  • project3 - веб-интерфейс для десктопного приложения
  • Справочная информация по fpCEF3
  • TChromium Options - опции компонента TChromium
  • TChromium Events - обработка событий Chromium
  •  
  • Vcorp.ru - Главная страница сайта
  • Тест больших гридов в перемещаемых окнах
  • Тестирование 3D графики в браузерах
  • «VcorpJS» - Главная страница раздела
  • «Vcorp Generator» - Главная страница раздела
  • Открывать окно навигации
    <<<
    Изменить высоту >>