Re: 1. Работа с DOM HTMLayout
От: Зверёк Харьковский  
Дата: 24.11.06 02:41
Оценка: 176 (12)
Управление всем UI происходит, как правило, работой с элементами DOM.
DOM (Document Object Model) — это дерево всех элементов, из которых состоит отображаемый HTML. В первом приближении можно считать, что один DOM-элемент соответствует одному теги исходного текста HTML, впрочем, из этого правила есть исключения (см. Примечание 1).

Изменение DOM (состава, внешнего вида, состояния) происходит только следующими способами (весь API для этого описан в заголовочном файле htmlayout_dom.h, тонкая C++-обертка "для примера" — htmlayout_dom.hpp):
0. Навигация по DOM — используется для того, чтобы найти элемент, который собираешься менять.
1. Добавление/удаление DOM элементов — используется, собственно, для изменения элементов UI.
2. Изменение HTML элементов DOM — альтернатива модификации DOM путем удаления/вставки элементов
3. Изменение текста элементов DOM
4. Изменение аттрибутов элементов DOM — используется для изменения представления элементов
5. Изменение состояния элементов DOM — используется для того, для чего и можно предположить по названию
6. Изменение "значения" (value) элементов DOM — быстрый способ изменения значимой части состояния элемента

Далее подробнее.

0. Навигация по DOM
Методы навигации:
* прямой перебор всех "детей" данной вершины: HTMLayoutGetChildrenCount, HTMLayoutGetNthChild
* прямой переход к родителю: HTMLayoutGetParentElement
* некоторые специальные функции: HTMLayoutFindElement (элемент в данной точке [x, y]), HTMLayoutGetFocusElement (текущий элемент в фокусе)
* поиск элемента по css-селектору — достаточно сложные функции, которые принимают на вход параметры для поиска и callback-функцию, которую надо вызвать для найденных элементов. Таких функций 3: HTMLayoutSelectElements (ищет вниз по DOM от заданного элемента), HTMLayoutSelectParent (ищет вверх по DOM), HTMLayoutVisitElements (ищет не по css-селектору, а по именам тагов и аттрибутов, которые могут содержать wildcards).

1. Добавление/удаление элементов
Реализуется, соответственно, функциями: HTMLayoutInsertElement, HTMLayoutDetachElement.
Полезно знать:
* элемент, удаленный из DOM, можно использовать и дальше (например, вставить в другое место DOM), пока он актуален. Актуальность контролируется счетчиком ссылок элемента (Примечание 2).
* элемент вставляемый в DOM при помощи HTMLayoutInsertElement, может быть:
а) совершенно новым элементом, созданным с помощью HTMLayoutCreateElement
б) элементом, ранее вытащенным из DOM с помощью HTMLayoutDetachElement
в) клоном существующего элемента, созданным с помощью HTMLayoutCloneElement.
* чтобы отсортировать элементы, лежащие в контейнере (например, строки в таблице), не нужно их все по очереди удалять из DOM и опять вставлять: для этого существует специальная функция HTMLayoutSortElements
* если нужно сделать элемент "временно невидимым", а потом опять показать (например, как реакцию на кнопку "Скрыть/Показать подробности"), то лучше делать это не удалением/вставкой, а с помощью изменения стилей (например, установить атрибут class в hidden, а в CSS прописать: ".hidden{display:none;}")
* некоторые изменения DOM вызывают side effects (вставку дополнительных, "синтетических" элементов). Например, если в таблицу с 5 колонками вставить tr, в котором всего 4 ячейки, в него добавится дополнительная, пятая синтетическая ячейка.
* находится ли данный элемент в DOM, и если да, то какого окна, можно узнать функцией HTMLayoutGetElementHwnd.
* порядковый номер данного элемента внутри его родительского элемнта можно узнать функцией HTMLayoutGetElementIndex.

2. Изменение HTML элементов DOM
Выполняется, естественно, функциями HTMLayoutGetElementHtml/HTMLayoutSetElementHtml.
Важно понимать, что не все прямые изменения HTML одинаково полезны (и безопасны). Например, попытка установить для элемента <tr> какой-нибудь другой html, кроме набора <td>, может привести к совершенно непредсказуемым последствиям.

Лично я предпочитаю использовать HTMLayoutSetElementHtml только в простейших случаях, когда нужно, скажем, в ячейке таблицы написать "немножко <b>жирного</b> текста", а все более глобальные изменения UI выполнять методами, описанными в разделе 1.

3. Изменение текста элементов DOM
Чтобы узнать текст, используются функции HTMLayoutGetElementText, HTMLayoutGetElementInnerText — первая вернет текст с "дырками" на месте дочерних элементов, вторая — полный текст. (например, для элемента "<p>some text with <b>bold</b> part</p>" первая вернет "some text with \0 part", вторая — "some text with bold part").

Чтобы изменить текст, используется функция HTMLayoutSetElementInnerText. Внимание! Все дочерние элементы будут удалены. (То есть вызывать эту функцию для <table> — не очень разумная идея).

Эти функции (как и большинство других функций HTMLayout) работают с текстом в кодировке UTF-8.

Существуют также UTF-16 варианты: HTMLayoutGetElementInnerText16, HTMLayoutSetElementInnerText16.

4. Изменение аттрибутов элементов DOM
Перебор всех аттрибутов: HTMLayoutGetAttributeCount, HTMLayoutGetNthAttribute
Запрос/установка значения аттрибута по имени: HTMLayoutGetAttributeByName, HTMLayoutSetAttributeByName.
Сброс всех аттрибутов: HTMLayoutClearAttributes.

БОльшую часть всех аттрибутов можно использовать разве что для изменения стиля элемента (например, установить элементу "class=red", если в CSS прописано ".red{color:red;}" и т.п.)

Впрочем, есть некоторые аттрибуты, которые обрабатывает сам HTMLayout, и их изменение вызовет side effects. Примеры:
* аттрибут src тега img (изменит отображаемую картинку)
* аттрибут fixedrows тега table (изменит количество "непрокручиваемых" строк таблицы)
* аттрибут type тега input (изменит тип элемента ввода)

5. Изменение состояния элементов DOM
HTMLayoutGetElementState/HTMLayoutSetElementState

Используется для запроса и установки состояний элементов, которые изменяются под действиями пользователя.
Например:
* выбранный чекбокс имеет состояние STATE_CHECKED
* элемент в фокусе имеет состояние STATE_FOCUS
* элемент, над которым находится мышка, имеет состояние STATE_HOVER
Вообще, все возможные состояния перечислены в enum ELEMENT_STATE_BITS в файле htmlayout_dom.h. Там же — подробные комментарии, какое состояние что означает.

Очевидно, что элемент может иметь несколько состояний одновременно (допустим, FOCUS | HOVER | CHANGED).

Полезные применения состояний:
* просто запросить (мышка над этим элементом?)
* установить (скажем, состояние VISITED для ссылки)
* использовать в CSS-селекторах (практически каждому STATE_XXXX соответствует CSS-селектор :xxxx) — таким образом можно, например, установить особый стиль для элемента, над которым мышь; или для нажатой кнопки (STATE_ACTIVE, :active) или для отключенного (STATE_DISABLED, :disabled)

Вообще, работа с состояниями идет согласно с человеческой логикой: если нужно изменить состояние некоего элемента (например, свернутый/развернутый для вершины дерева), нужно в первую очередь поискать соответствующую константу STATE (STATE_COLLAPSED/STATE_EXPANDED).


6. Изменение "значения" (value) элементов DOM
HTMLayoutControlGetValue/HTMLayoutControlSetValue — удобные "шорткаты" для работы с элементами ввода, позволяет однообразно запросить/установить значение для разных элементов. Все, что делается этими функциями, может быть сделано и без них (но несколько менее удобно).

Например:
* для поля ввода текста, value — это и будет вводимый текст; его также можно запросить/установить с помощью GetText/SetText
* для чекбокса, value — булевое значение "выбран/не выбран"; его также можно запросить/установить с помощью GetState/SetState (STATE_CHECKED)
* для списка, value — это выбранная option; чтобы узнать ее "руками", надо найти option со state = STATE_CHECKED
и т.п.

Некоторые дополнительные сведения
* в htmlayout_dom.h определено еще несколько полезных функций. Часть из них я опишу в следующих главах — работа с behaviors и events, работа с popup-ами; другую часть (HTMLayoutScrollToView и т.п.) оставляю для самостоятельного изучения.
* все функции htmlayout_dom.h возвращают HLDOM_RESULT; возможные его значения можно посмотреть все в том же файле. Кодом успеха являются HLDOM_OK, HLDOM_OK_NOT_HANDLED, все остальные — коды ошибки (операция не удалась). Впрочем, из этого правила есть исключения: например, функция HTMLayoutGetElementHwnd на "детачнутом" элементе вернет HLDOM_INVALID_HWND, что можно считать не ошибкой, а просто символом "неприаттаченности элемента".

Все, на сегодня хватит.



Примечание 1
В первом приближении можно считать, что один DOM-элемент соответствует одному теги исходного текста HTML, впрочем, из этого правила есть исключения . Например, вот такой исходный HTML:
<select>
  <option>1</option>
  <option>2</option>
  <option>3</option>
</select>

(выпадающий список с 3-мя элементами) "на самом деле" преобразуется вот в такой:
<select>
  <caption></caption>
  <select>
    <option>1</option>
    <option>2</option>
    <option>3</option>
  <select>
</select>

В некоторых случаях этот нюанс оказывается важным.

Примечание 2
Элементы DOM HTMLayout — это объекты со счетчиками ссылок, они удаляются, когда счетчик ссылок равен 0. Пользователь может контролировать счетчик ссылок функциями HTMLayout_UseElement, HTMLayout_UnuseElement. Пока элемент находится в DOM, счетчик ссылок у него > 0. Если пользователь удалил элемент из DOM (HTMLayoutDetachElement), то его можно продолжать использовать дальше, пока счетчик ссылок > 0.
FAQ — це мiй ай-кью!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.