HTML и Кларион

Часть 1: основы

HTML это простой язык разметки. Совместно с CSS и JavaScript уже можно создавать интерактивные страницы и страницы с оригинальным красивым дизайном. Глубоких знаний при этом не требуется. А web-интерфейс достаточно часто применяется при разработке программ. Применение html-страниц позволяет освежить аскетичный набор контролов Клариона.

Показать html-страницу в Кларион не составляет труда. Для этого можно использовать ole-контрол Shell.Explorer.2. Этот контрол присутствует на всех компьютерах с установленным браузером Internet Explorer. Как известно, по умолчанию IE установлен на всех компьютерах с ОС Windows. Т.е. этот контрол есть всегда и везде.

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

?OLE{'Navigate("file://' & CLIP(inFileName) & '")'}

Основой любого html-документа являются ссылки. И основная задача состоит в том, чтобы перехватить нажатие на ссылке в html-документе и выполнить свое действие. Это достигается при помощи определения процедуры обработки событий для ole-контрола:

OCXREGISTEREVENTPROC(?OLE, MyOleEventFunc)

MyOleEventFunc – это процедура обработки событий, определяемая пользователем. Эта процедура имеет определенный прототип:

MyOleEventFunc PROCEDURE(*SHORT inReference, SIGNED inOleControl, LONG inCurrentEvent),LONG

Описание параметров привожу из стандартной помощи по Кларион 6:

The parameters it receives from the operating system are:

*SHORT A Reference parameter to pass onto the following other OCX library procedures: OCXGETPARAM, OCXGETPARAMCOUNT, and OCXSETPARAM as their first parameter.

SIGNED The field number for the control. This is the same number that is represented by the control’s field equate label.

LONG The number of the .OCX event. Equates for some pre-defined event numbers are contained in the OCXEVENT.CLW file.

The LONG return value indicates to the operating system whether any further processing is necessary. Returning zero (0) indicates some further processing is necessary(like updating a USE variable or unchecking a radio button), while returning any other value indicates processing is complete.

Processing the events generated by an .OCX control must occur quickly, since some events have critical timing. Therefore, there should be no user interaction possible within this procedure (such as WINDOWs, ASK statements, or MESSAGE procedures). The code should process only what it needs to, just as quickly as possible (usually, this means eliminating all mouse events).

Для примера рассмотрим следующую html-страницу:

<html>
<body>
<a href="CLICK://I_WANNA_CATCH_THIS_LINK">Try me</a>
</body>
</html>

Код для перехвата нажатия на ссылку:

MyOleEventFunc PROCEDURE(*SHORT inReference, SIGNED inOleControl, LONG inCurrentEvent) ! ,LONG
loc:Event CSTRING(1024)
loc:Link CSTRING(1024)
CODE
loc:Event = inOleControl{PROP:LastEventName}
IF CLIP(loc:Event) = 'BeforeNavigate2'
  loc:Link = OCXGETPARAM(inReference, 2)
  IF SUB(UPPER(loc:Link),1,8) = 'CLICK://'
    loc:Link = SUB(loc:Link, 9, LEN(loc:Link) - 9) ! cut the 'CLICK://'
    IF UPPER(loc:Link) = 'I_WANNA_CATCH_THIS_LINK'
      MESSAGE('CATCH IT')
    END
    OCXSETPARAM(inReference, 7, 1) ! cancel navigate
  END
END

И это все! Этих знаний достаточно для применения html-страниц в кларион-коде.

Часть 2: усложняем

«Всю жизнь мечтал» о реализации своего рабочего стола:

desktop_orig

Здесь основная проблем состоит в корректном отображении иконок действий при ресайзе окна.

desktop_resizeТо, что достаточно громоздко реализовать в Кларион, легко получается в html.

В примере представлен класс CFCHTMLClass (cfchtml.inc, cfchtml.clw), который реализует возможность отображения и обработки нажатий на ссылки html-документа. Помимо этих действий, класс решает две известные мне проблемы.

Во-первых, контрол Shell.Explorer.2 имеет стандартное контекстное меню IE. И необходимо заблокировать это меню.

Во-вторых, когда фокус находится внутри ole-контрола, такие клавиши как Esc, Ctrl+F4, Ctrl+F6, F10 и тому подобные обрабатываются самим контролом, а не окнами Кларион. Соответственно, необходимо перехватить нажатия этих клавиш и передать их в Кларион окно.

Если посмотреть на окно ПОСЛЕ загрузки html-страницы, то увидим следующее:

olewindows

Желтым цветом выделены непосредственно ole-контрол Клариона и окно с классом Internet Explorer_Server.

Все «настоящие» действия, т.е. отображение и обработка событий, происходят в окне Internet Explorer_Server.

Также из рисунка выше видно, что Ole-контрол никак иерархически не связан с окном Internet Explorer_Server. На данный момент я не знаю, как сопоставить эти окна, используя только технологию OLE.

Для перехвата контекстного меню и нажатий служебных клавиш, необходимо поймать события WM_RBUTTONUP, WM_CONTEXTMENU и WM_KEYDOWN, WM_KEYUP, поступающие в окно Internet Explorer_Server. Для этого необходимо засабклассить это окно.

Как вы понимаете, мы можем положить на окно несколько html-документов. И, естественно, необходимо засабклассить каждое окно. Еще раз обращу внимание на то, что окно Internet Explorer_Server появляется динамически только после загрузки в него html-документа.

Для сабклассинга необходимо найти все окна с классом Internet Explorer_Server. Это достигается использование API EnumChildWindows и GetClassName. Повторный сабклассинг необходимо исключить. Все найденные окна сохраняются в очередь. Пробежав по очереди сабклассим каждое окно и выставляем в этой же очереди флаг, если окно уже было засабклашшено, то проверив флаг, пропускаем его.

Для сабклассинга используется класс CFCWndProc (CFCWndProc.inc, CFCWndProc.clw) описание, которого не входит в рамки этой статьи.

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

Код реализующий вышесказанное можно посмотреть в файле cfchtml.clw, это методы CFCHTMLManagerClass.SetIEsCallback и процедура CFC_HTMLEnumerateWindows.

Код процедуры сабклассинга достаточно прост:

CFCHTMLCallbackClass.CallBackProc PROCEDURE(ULONG hWnd,ULONG inMsg,ULONG wParam,LONG lParam)
loc:WM_RBUTTONUP EQUATE(0205h)
loc:WM_CONTEXTMENU EQUATE(07Bh)
loc:WM_KEYDOWN EQUATE(0100h)
loc:WM_KEYUP EQUATE(0101h)
CODE
CASE inMsg
OF loc:WM_RBUTTONUP OROF loc:WM_CONTEXTMENU
  RETURN FALSE
OF loc:WM_KEYDOWN
  CFC_PostMessage(0{PROP:Handle},loc:WM_KEYDOWN,wParam,lParam)
  RETURN FALSE
OF loc:WM_KEYUP
  CFC_PostMessage(0{PROP:Handle},loc:WM_KEYUP,wParam,lParam)
  RETURN FALSE
END
RETURN PARENT.CallBackProc(hWnd,inMsg,wParam,lParam)

Оставшиеся мелочи

Shell.Explorer.2 имеет те же свойства, которые указаны в Панели управления/Свойства обозревателя. Это означает, что если отключено отображение картинок в IE, то и в своем окне они будут отключены. Это необходимо учитывать при создании html-документа и, возможно, предупреждать об этом конечного пользователя.

PNG–формат предпочтителен для отображения картинок. Нормальная поддержка формата появилась в IE версии выше 6. Потому рекомендуется обновить браузер до последней доступной версии. Не стоит забывать также, что используемые изображения, необходимо также копировать конечному пользователю.

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

В классе сделаны дополнительные методы IsImagesEnabled, GetIEVersion и DisableClickSound, работа которых основана на работе с реестром.

И последнее вы можете создавать html-документ динамически, это ведь просто текстовый документ. А после создания загружать его в ole-контрол.


Покопались с данной технологией и набрели на следующие вопросы:

Интересно, можно ли сделать что-то похожее на AJAX. Т.е. подгружать данные из клариона на web-страничку без ее перезагрузки…

HTML и Кларион (687)

Старые комментарии

Второе, можно ли из клариона вызвать javascript функцию. Подозреваю, что можно. Пробовал

?OleControl{‘Document.InvokeScript(«somefunc();»)’}
?OleControl{‘Document.InvokeScript(«somefunc()»)’}
?OleControl{‘Document.InvokeScript(«somefunc»)’} и тому подобное, но чего-то не получается. В C# в WebBrowser (что, наверное, есть тот же самый IE) можно вызвать webbie.Document.InvokeScript(«somefunc»); и все нормально работает…

Зря беспокоил
1) можно использовать функцию Document.GetElementByID например, inOleControl{‘Document.GetElementByID(«menu1″).innerHTML’} = ‘»123″‘ или см. п2
2) Document.ParentWindow.execScript например, inOleControl{‘Document.ParentWindow.execScript(«somefunc(122);»,»javascript»)’}
Этими двумя функциями можно добиться эффекта, похожего на AJAX

HTML и Кларион: 4 комментария

  1. admin

    Статья была на другом сайте, Андрея Попова. Все снесено без бекапа.
    Восстановил с http://wayback.archive.org
    Только вот картинки и файлы они не бекапят.
    Спасибо.

  2. ingasoftplus

    Спасибо! Я думал что статья — просто ссылка на нее!! (ну а пробую коменты 🙂 )

  3. admin

    Да. Это была просто ссылка. Но я плагином проверяющим битые ссылки автоматом, снес ее не подумав посмотреть.

Комментарии запрещены.