Введение

Эта глава описывает основы работы с HTMLayout.

Внимание!

  1. Объяснения и примеры кода расчитаны на использование голого WinAPI, и, я надеюсь, могут быть без труда применены для MFC, WTL и прочих оберток. Если есть желающие поделиться примерами для других случаев, можно писать мне.
  2. Объяснения и примеры расчитаны на использование оконной (windowed) версии библиотеки, примеры для HTMLite (window-less версия) могут отличаться существенно.
  3. Использование примеров и объяснений предполагает некоторое знакомство с основами программирования. То есть примеры не доводились до состояния “просто скопируй и скомпилируй это”, они лишь показывают основные принципы. Именно поэтому приводятся только те фрагменты кода, которые относятся непосредственно к использованию HTMLayout, предполагается, что читатель сам знает, как создать главную функцию, как создать обработчик событий Windows, как регистрировать оконные классы и т.п.

Поехали.

Основы

Использование HTMLayout в качестве интерфейсной библиотеки предполагает следующие шаги:

  1. создать экземпляр HTMLayout;
  2. загрузить в него содержимое;
  3. передать библиотеке события Windows;
  4. обработать сообщения и нотификации библиотеки;
  5. по необходимости, изменять содержимое окна.

Дескриптором экземпляра HTMLayout является обычный дескриптор окна (HWND).

Чтобы создать экземпляр HTMLayout, можно либо создать новое окно, либо “прицепить” библиотеку к уже существующему.

Создание экземпляра HTMLayout и загрузка контента

Метод 1. Создание нового окна

Создаем окно:
HWDN hHtmlayoutWnd = CreateWindow(HTMLayoutClassNameT(), ...);
 
//загрузка интерфейса из файла
HTMLayoutLoadFile(hHtmlayoutWnd, L"путь/к/файлу/в/кодировке/UTF-16");
//или загрузка интерфейса из строки
HTMLayoutLoadHtml(hHtmlayoutWnd, html_string_in_utf8_encoding, length_of_string_in_bytes);

Метод 2. "Прицепление" к существующему окну (htmlayout mix-in)

Как правило при использовании htmlayout c GUI библиотеками (frameworks) типа MFC или WxWidgets удобнее “подмешать” функциональность htmlayout к уже существующему классу окна. Для этого достаточно в оконную процедуру окна (WndProc) добавить обработчик событий HTMLayout - до любых своих обработчиков.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  LRESULT lResult;
  BOOL    bHandled;
 
  lResult = HTMLayoutProcND(hWnd,message,wParam,lParam, &bHandled);
  if(bHandled)      //если флаг handled установлен в TRUE
    return lResult; //значит вся необходимая обработка уже выполнена
 
  //собственные обработчики
  switch (message) 
  {
  //...
    case WM_CREATE:
    {
	  //загрузка интерфейса из файла
	  HTMLayoutLoadFile(hHtmlayoutWnd, L"путь/к/файлу/в/кодировке/UTF-16");
	  //или загрузка интерфейса из строки
	  HTMLayoutLoadHtml(hHtmlayoutWnd, html_string_in_utf8_encoding, length_of_string_in_bytes);
	  break;
	}
  //...
  }
  return 0;
}

HTMLayoutProcND обработает все события отрисовки и низкоуровневого пользовательского ввода (события клавиатуры и мыши), и даст вам возможность обработать остальные.

Дескриптор HTMLayout в этом случае совпадает с дескриптором того окна, к которому он “прицеплен”.

htmlayout mix-in метод это единственный способ “подмешивания” HTML функциональности к окну диалога (dialog window) без создания дополнительного дочернего окна.

DOM

Теперь у вас на экране должно быть окно, в которое загружен ваш интерфейс (если вы все сделали правильно и не забыли вызвать ShowWindow).

Для того, чтобы двигаться дальше, надо понимать, что собой представляет “объектная модель” этого интерфейса. С точки зрения HTMLayout, в нее загружен документ, представленный “деревом” элементов (элементы DOM, Document Object Model elements). Каждый элемент в дереве соответствует одному тегу в исходном html-документе (это правило выполняется не всегда, исключения рассматриваются в следующей главе). Чтобы изменить внешний вид вашего интерфейса, как правило, нужно менять текст или аттрибуты элементов DOM, или удалять из дерева одни элементы и вставлять другие. Назначение обработчиков событий тоже выполняется относительно этих элементов.

Ниже описаны некоторые основы, подробнее работа с элементами DOM рассматривается в следующей главе.

Как получить элемент DOM

Для того, чтобы получить доступ к дереву элементов нашего интерфейса, мы можем запросить “корневой” элемент: Plain С:

HELEMENT hRoot = NULL;
HTMLayoutGetRootElement(hWnd, &hRoot);
 
HTMLayoutUseElement(hRoot);
// работа с hRoot...
HTMLayoutUnuseElement(hRoot);
C++:
using namespace htmlayout;
dom::element root = dom::element::root_element(hWnd);
// работа с root...
:!: класс htmlayout::dom::element это так называемый smart pointer который помимо всего прочего инкапсулирует вызовы функций HTMLayoutUse/UnuseElement.

Имея корневой элемент, мы можем запросить любой элемент дерева при помощи различных функций навигации и поиска, например:

//запросим один из непосредственных дочерних элементов
HELEMENT hBody;
//поскольку hRoot соответствует тегу <html>,
//его второй дочерний элемент будет соответствовать тегу <body>
HTMLayoutGetNthChild(hRoot, 1, &hBody); 
 
//найдем первый элемент div с аттрибутом class = sidebar
HELEMENT hDiv;
HTMLayoutSelectElements(
  hRoot,         //откуда начинать искать
  "div.sidebar", //CSS-селектор того, что мы ищем
  &first_finder, //функция, в которую будут передаваться найденные элементы
  &hDiv	         //этот параметр будет передан в first_finder, 
                 //сюда функция запишет адрес найденного элемента
);

вот так может выглядеть функция first_finder из примера выше:

BOOL CALLBACK HTMLayoutElementCallback( HELEMENT he, LPVOID toStore )
{
  *((HELEMENT*)toStore) = he; //запишем адрес найденного элемента
  return TRUE;                //вернем TRUE как сигнал, что дальше перебирать не надо.
}

На С++ вышеприведенный фрагмент может быть записан несколько короче :-) :

using namespace htmlayout;
dom::element sidebar = root.find_first("div.sidebar");

Что можно сделать с полученным элементом

Можно поменять текст или HTML элемента:

HTMLayoutSetElementInnerText(hDiv, (LPCBYTE)"Hello, World!");
HTMLayoutSetElementHtml(hDiv, (LPCBYTE)"Hello, <b>World</b>!", 20, SIH_REPLACE_CONTENT); 

Можно запросить или поменять один из его аттрибутов:

LPWSTR attr_value;
HTMLayoutGetAttributeByName(hDiv, "class", &attr_value);
HTMLayoutSetAttributeByName(hDiv, "class", L"new-class");

Можно удалить элемент:ы

HTMLayoutDeleteElement(hDiv);

Или создать и вставить в него дочерние элементы:

HELEMENT hP;
HTMLayoutCreateElement("p", L"This is new paragraph", &hP);
HTMLayoutInsertElement(hP, hDiv, 0); //вставим новый абзац как первый элемент нашего div

  1. Обращайте внимание на кодировки передаваемых строк. В большинстве случаев, HTMLayout использует одну из двух - либо UTF8, либо UTF16. Обратите внимание, что в UTF8 идет 1 байт на английскую букву и 2 байта - на русскую.
  2. Большинство изменений в интерфейсе не отобразится, пока интерфейс не будет обновлен. Это происходит при изменении размеров окна, либо вручную:

//допустим, мы изменили содержимое элемента hDiv, когда все готово, вызовем:
HTMLayoutUpdateElement(hDiv, TRUE);

Обработка событий

Чтобы назначить элементу интерфейса обработчик событий, существуют два способа: непосредственное назначение обработчика и связывание элемента с behavior (поведением).

Подробно обработка событий описана в главе Обработка событий, ниже всего несколько примеров.

Назначение обработчиков событий

Допустим, у нас есть некий элемент hButton, для которого мы хотим обработать событие “mouse down”. Выглядеть это будет примерно так:

//код функции-обработчика события:
BOOL CALLBACK MouseHandler(LPVOID tag, HELEMENT target, UINT event, LPVOID prms )
{
  switch( evtg )
  {
    case HANDLE_MOUSE:
    {
      MOUSE_PARAMS *p = (MOUSE_PARAMS *)prms; //специфичные для мыши параметры
 
      switch(p->cmd) //вот это - конкретное событие
	  {
	    case MOUSE_DOWN:
		  //делаем то, зачем сюда пришли - обрабатываем событие
		  return TRUE;
	  }
    }
  }
 
  return FALSE;
}
 
//привязка обработчика к элементу:
HTMLayoutAttachEventHandlerEx(
   hButton,         //к кому цепляем обработчик
   &MouseHandler,  //адрес обработчика
   NULL, 
   HANDLE_MOUSE     //какого рода события хотим обрабатывать
);

Работа с behaviors

Behavior (“поведение”) можно рассматривать как набор связанных обработчиков различных событий, относящихся к поведению одного элемента интерфейса. Например, “поле ввода” с точки зрения HTMLayout представляется как элемент <input type=“text”>, которое обрабатывает события мыши (изменяется положение каретки), клавиатуры, получения или потери фокуса и т.п. Каждый behavior в HTMLayout имеет свое имя, и связывается с каким-нибудь элементом интерфейса декларацией в таблице стилей. Например:

p.editable{
  behavior: edit;
}
Теперь у любого абзаца с аттрибутом class=editable установлено поведение “строка ввода” - их можно редактировать. В ядре HTMLayout есть несколько встроенных поведений (edit, select, number и т.п.), но вы можете легко определить свои собственные. Для этого нужно обработать “уведомление” (notification) HLN_ATTACH_BEHAVIOR - см. ниже.

Изменение поведения HTMLayout

HTMLayout предоставляет программисту богатые возможности для изменения (перехвата) различных аспектов своего поведения. Например, можно перехвататить загрузку различных ресурсов, на которые ссылается HTML-файл (через img src=… или link src=…); создание контролов (например, ActiveX); подключение поведений; начало и окончание загрузки различных данных… Для всего этого существуют уведомления (notifications).

Для того, чтобы получать уведомления от HTMLayout, нужно в начале работы установить свой обработчик уведомлений:

HTMLayoutSetCallback(hWnd, &HTMLayoutNotifyHandler,0);

Вот таким может быть код обработчика:

LRESULT CALLBACK HTMLayoutNotifyHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LPVOID vParam)
{
  NMHDR*  phdr = (NMHDR*)lParam;
 
  switch(phdr->code)
  {
    case HLN_CREATE_CONTROL:    //обрабатываем создание нестандартного контрола
    case HLN_ATTACH_BEHAVIOR:   //обрабатываем запрос на подключение поведения
    case HLN_LOAD_DATA:         //обрабатываем запрос на загрузку каких-нибудь данных,
	                            //например, картинки - можем загрузить ее из ресурсов
								//или БД
  }
  return 0;
}

Стоп.

Вывод - это место, где автор устал писать. Похоже, описание получилось довольно сумбурным и неполным. Я очень надеюсь, что по мере появления вопросов у читателей и свободного времени у автора оно будет улучшаться и пополняться. Не стесняйтесь писать htmr-tutorial (сабака-барабака) imho.com.ua

htmlayout/tutorial-basics-r.txt · Last modified: 2007/09/21 22:39 (external edit)
chimeric.de = chi`s home Creative Commons License Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0