Сообщений 3 Оценка 100 [+0/-1] Оценить |
Введение Примеры применения web-интерфейса Отображение HTML с помощью CHtmlView Обработка событий HTML-окна CHtmlDialog - диалоговое окно на основе HTML Ссылки Книги по JScript/VBScript и DHTML : |
Демонстрационное приложение – исходные коды
Демонстрационное приложение – исполняемый файл
В данной статье описаны способы использования MFC-класса CHtmlView и технологии DHTML для создания web-интерфейса в MFC приложении. Под формулировкой «приложение с Web-интерфейсом» я подразумеваю то, что пользовательский интерфейс или его часть в приложении создан на основе HTML. При попытке применить такой интерфейс в MFC-приложении я столкнулся с следующими проблемами:
Для решения таких вопросов MSDN (см. Handling HTML Element Events) советует применять COM-интерфейсы DHTML. Мне показалось, что это плохая альтернатива классической модели взаимодействия с GUI-интерфейсом в MFC (карты событий, и прямое манипулирование через SendMessage или объекты элементов GUI).
В этой статье приводится описание некоторых методик, облегчающих создание Web-интерфейса и работу с ним из MFC-приложений, а именно:
В качестве примера рассмотрим задачу разработки MFC-класса (CHtmlDialog) для создания диалогового окна с web-интерфейсом.
ПРИМЕЧАНИЕ Для ознакомления с понятием Web-интерфейса советую прочитать статью “Браузер в каждом окне”, в которой не только хорошо описано это явление, но и показаны приемы реализации Web-интерфейса в MFC-приложении. |
К статье прилагается архив с классом CHtmlDialog и примерами его использования.
Впервые Web–интерфейс для настольных приложений был применен в приложениях Microsoft, которые входят в состав ОС Windows.
Рисунок 1. Web-интерфейс в справочном окне Windows XP.
Рисунок 2.Web–интерфейс в программе Norton-AntiVirus.
Рисунок 3. Web–интерфейс в части окна - отображение Совета (Did you know …)
Отобразить HTML в MFC-приложении довольно просто, для этого надо использовать класс ChtmlView. Создайте новый проект с помощью помощника “MFC AppWizard (exe)” и выберите Single Document. Включите поддержку архитектуры Document View. На последней странице помощника для класса ХххView установите CHtmlView как базовый класс (список Base Class), а затем добавьте в ресурсы приложения HTML-страничку.
Для того чтобы программа была больше похожа на приложение Windows, чем на окно Internet Explorer, необходимо кое-что подправить в HTML-страничке:
ПРИМЕЧАНИЕ Последние два пункта довольно спорны – так как неудобства пользователю они причинить могут, а пользу – вряд ли. В общем, на вкус и цвет... – прим.ред. |
Далее приведен DHTML-код, реализующий данные исправления. Такие действия возможны благодаря технологии DHTML.
... <SCRIPT LANGUAGE="JScript"> // Запретить пользователю выделение контента мышью // (разрешить выделять текст только в EditBox)function onSelect1() { if (window.event.srcElement.tagName !="INPUT") { window.event.returnValue = false; window.event.cancelBubble = true; } } // Запретить контекстное меню IE (разрешить только в EditBox)// (если все-таки надо показать настоящее меню, -// надо использовать Advanced Hosting Interfaces)function onContextMenu() { if (window.event.srcElement.tagName !="INPUT") { window.event.returnValue = false; window.event.cancelBubble = true; returnfalse; } } // При загрузке HTML установить обработчики Контекстного Меню и Выделения.// function onLoad() { // для текста на HTML запретить менять курсор // (кроме Поля ввода "INPUT" и ссылки "A")var Objs = document.all; for (i = 0; i < Objs.length; i++) // Поля ввода "INPUT" и ссылки "A"if (Objs(i).tagName != "INPUT" && Objs(i).tagName != "A") Objs(i).style.cursor = "default"; // обработчик события – начало выделения HTML-области document.onselectstart = onSelect1; // обработчик события – контекстное меню document.oncontextmenu = onContextMenu; } </SCRIPT> </head> <BODY onload="onLoad();" leftmargin=0 topmargin=0 rightmargin=0 bottommargin=0 style = "background-color: buttonface;"> <!-- фон HTML области будет таким же, как у всех диалогов --> ... |
Итак, мы создали приложение, которое использует в качестве интерфейса HTML. Меню, Панель инструментов и строка состояния остались, но это нормально, т.е в приложении можно не отказываться от традиционных элементов управления, что дает определенную гибкость.
ПРИМЕЧАНИЕ Здесь мы столкнулись с технологией DHTML, благодаря которой вообще все это возможно. Сама технология DHTML возможна благодаря технологии DOM (Document Object Model). DOM представляет HTML-документ в виде объектов (см. MSDN Library). |
Типичный сценарий работы с элементами интерфейса предполагает получение событий от них (например, от кнопок), и установку данных (например текст в поле ввода). Конкретно в нашем случае необходимо организовать взаимодействие HTML-окна с MFC-кодом. Это реализовать не сложно – идея состоит в том, чтобы передавать событие от HTML в MFC-код с помощью функции OnBeforeNavigate2 класса CHtmlView (см. HTML—The MFC-Way)
ПРИМЕЧАНИЕ В DHTML тоже есть такое понятие как событие. Возможности событийной модели в DHTML очень широки, например, событие можно остановить на определенном этапе обработки. |
При возникновении HTML-события его можно трансформировать в вызов window.navigate(%строка%). MFC-код получит такое событие в виде вызова OnBeforeNavigate2. В строке можно передать любые параметры, таким образом, MFC-код сможет обработать ситуацию.
Передача события о Нажатии на кнопку Ok, вместе с событием передается и текст из поля txtBox:
<SCRIPT LANGUAGE="JScript"> function onBtnOk() { var Txt = txtBox.value; // строка из TextBox// "app:1005@" - это префикс команды для MFC кода.// Txt - вместе с событием можно передать данные window.navigate("app:1005@" + Txt); } </SCRIPT> <BODY> <input type=text style="width:50" id=txtBox > <!-- у кнопки есть обработчик события – скрипт функция onBtnOk() --> <input type=BUTTON value="Ok" onClick="onBtnOk()" style="width:45%"> </BODY> </HTML> |
Код обработки события в классе CHtmlView:
void CHtmlCtrl::OnBeforeNavigate2( LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel) { constchar APP_PROTOCOL[] = "app:"; int len = _tcslen(APP_PROTOCOL); if (_tcsnicmp(lpszURL, APP_PROTOCOL, len)==0) { OnAppCmd(lpszURL + len); // конкретная реакция приложения на событие *pbCancel = TRUE; // Отмена события BeforeNavigate2, иначе будет ошибка } CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel); } |
Поскольку источником событий может быть не только HTML, но и MFC-код, надо, чтобы MFC-код мог обращаться к HTML (MFC -> HTML). Кроме событий, MFC-код должен иметь возможность передавать данные в HTML. Чтобы это стало возможным, можно вызывать скрипты (Jscipt\VBScript) в HTML и передавать им данные в качестве параметров. Идея и реализация этого метода принадлежат Eugene Khodakovsky – см. JavaScript Calls from C++ .
Получение объекта «Скрипт» из HTML:
void CHtmlCtrl::OnDocumentComplete(LPCTSTR lpszURL) { HRESULT hr; hr = GetHtmlDocument()->QueryInterface(IID_IHTMLDocument, (void**)&m_pDocument); if (FAILED(hr)) { m_pDocument= NULL; return; } IDispatch *disp; m_pDocument->get_Script(&disp); } |
MFC-код, который вызывает конкретную функцию скрипта с параметрами:
CStringArray strArray; strArray.Add("String 1"); strArray.Add("String 2"); strArray.Add("String 3"); // вызов функции SetParameters в скрипте и передача Массива строк в HTML код m_HtmlCtrl.CallJScript2("SetParameters", strArray); // внутри функции CallJScript2:// GetIDsOfNames() – получить номер скрипт-функции по имени// Invoke() – вызвать скрипт-функцию по номеру |
Скрипты в HTML являются очень мощным и легким в использовании средством. С помощью них можно написать целую программу, которая будет управлять содержимым HTML-страницы и реагировать на действия пользователей. Обьектная структура DHTML (DOM) делает это программирование достаточно легким.
СОВЕТ Таким образом, можно часть MFC-кода, которая отвечает за интерфейс и действия пользователя, перенести в HTML-скрипт. А если HTML-странички держать отдельно от приложения, то можно менять логику интерфейса, не перекомпилируя EXE-файл. |
В любом приложении кроме главного окна есть еще и диалоги. Эти диалоги могут обладать достаточно сложным пользовательским интерфейсом. Я имею в виду не только сам дизайн, но и реакцию на действия пользователя. Здесь тоже есть смысл использовать DHTML. Проблема, которая здесь возникает (как разместить в диалоговом окне класс, производный от CView) решена в статье Microsoft Systems Journal, January 2000, Q&A C++, CHtmlCtrl by Paul DiLascia. Paul DiLascia создал класс CHtmlCtrl (производный от CHtmlView), который можно разместить на диалоге.
Созданный мной класс СHtmlDialog решает две задачи – установку имени диалогового окна и его размеров. Эти параметры указаны в HTML-страничке. Использование класса СHtmlDialog:
1. Вставить в ресурсы диалоговое окно и разместить на нем STATIC-control (вместо этого control-а будет HTML-страничка). На основании этого диалога создать MFC-класс (унаследованный от CDialog).
3. В заголовочном файле (например, Dlg4.h) изменить базовый класс на CHtmlDialog.
class CDlg4 : public CHtmlDialog // Теперь наследуем класс от CHtmlDialog { ... |
4. В CPP файле (например Dlg4.cpp) в конструкторе класса Dlg4 добавить вызов конструктора CHtmlDialog :
CDlg4::CDlg4(CWnd* pParent /*=NULL*/) // передача ресурса с HTML страничкой : CHtmlDialog(CDlg4::IDD,pParent, IDR_HTML4, IDC_STATIC1) { //{{AFX_DATA_INIT(CDlg4)// NOTE: the ClassWizard will add member initialization here//}}AFX_DATA_INIT } |
Класс СHtmlDialog позволяет также изменять размеры окна из HTML-кода (см. _onHtmlCmd в СHtmlDialog).
Рисунок 4. Скриншоты Диалогового окна.
Итак, почти все готово, но остаются еще две проблемы:
Если первое еще можно перетерпеть, то вторая проблема очень серьезна. Возможна такая ситуация, что приложение будет выглядеть по-разному в зависимости от настроек IE у пользователя.
Рисунок 5.
Вот так будет выглядеть HTML-диалог, если пользователь изменит настройки отображения в свойствах IE .
Чтобы преодолеть эти проблемы, необходимо реализовать поддержку Advanced Hosting Interfaces.
ПРИМЕЧАНИЕ Возможно, несколько проще это сделать с помощью CSS – прим. ред. |
Advanced Hosting Interfaces (AHI) – это COM-интерфейсы ActiveX-элемента WebBrowser (начиная с версии 4.0). Они помогают получить полный контроль над элементом WebBrowser. Реализация AHI в MFC-приложениях и преимущества этих интерфейсов хорошо продемонстрированы в примерах к http://www.beginthread.com/Contributor/Ehsan/ViewAllArticles.
Описанные проблемы решаются переопределением событий OnGetHostInfo и OnGetOptionKeyPath (см. Html_Host_Handlers.cpp).
На этом я поставлю точку. Спасибо за внимание.
Сообщений 3 Оценка 100 [+0/-1] Оценить |