JavaScript и MFC. Интеграция Property Tree в MFC приложение.

В одной из предыдущих статей я писал об использовании HTML-интерфейса в программах на MFC. Представленны в ней модифицированный класс CHtmlView, позволяет использовать широкий спектр возможностей, предоставляемых web-интерфейсом, сократить время разработки компонент отвечающих за внешний вид программы, а так же обеспечить простоту использования ранее написанного кода в других проектах.

Теперь перед Вами логическое продолжение, которое показывает использование HTLM-интерфейса на примере JavaScript-класса, реализующего дерево свойств

Прежде всего необходимо сказать несколько слов о взаимодействии JavaScript и С++ кода, который осуществляется с помощью MFC класса CHtmlView и двух его методов: Navigate и OnBeforeNavigate2. Ниже приведена соответствующая диаграмма.

Для передачи данных между JavaScript и С++ используется форматированная строка, в которой последовательно указываются пары имя – значение, а в качестве разделителя используется первый символ такой строки, например:

  1.  
  2. CString str = "";
  3. str += ":obj:";
  4. str += m_treeView->GetParam("obj");
  5. str += ":attrib:";
  6. str += m_treeView->GetParam("attrib");
  7. str += ":value:";
  8. str += m_treeView->GetParam("value");
  9. m_mainView->CallJavaScript("MFCSetAttrib", str);
  10.  
  11.  

Вызов функции CallJavaScript в последней строке приведет к запуску функции MFCSetAttrib, которой в качестве параметра будет передано значение переменной str.

Вышеупомянутая функция MFCSetAttrib, наряду с MFCCallMethod, реализуют доступ к объектам JavaScript из C++ кода. Стоит отметить, что доступ осуществляется по имени объекта с использование функции eval().

  1.  
  2. //Sets object attribute
  3. function MFCSetAttrib(str)
  4. {
  5. var params = ParseParams(str);
  6. var obj = document.getElementById(params['obj']);
  7. if(obj != null)
  8. {
  9. var searchStr = "%20";
  10. var replaceStr = " ";
  11. var re = new RegExp(searchStr , "g");
  12. var value = params['value'].replace(re, replaceStr);
  13. eval('obj.' + params['attrib'] + ' = "' + value + '";');
  14. }
  15. }
  16.  
  17. //Call object method
  18. function MFCCallMethod(str)
  19. {
  20. var params = ParseParams(str);
  21. eval(params['obj'] + '.' + params['method'] + '("' + params['value'] + '");');
  22. }
  23.  
  24.  

В предыдущей статье о JavaScript Property Tree формирование дерева и управление свойствами тестовой таблицы осуществлялось с помощью JavaScript кода, теперь же, дабы показать принципы взаимодействия, обе эти функции перенесены в С++. Естественно подобный перенос не мог сохранить ранее написанный код неизменным, а потому потребовалось добавить несколько новых возможностей, например, создание узла дерева из строки.

  1.  
  2. /**
  3.   * Creates PropTree item from string
  4.   *
  5.   * @param string item definition
  6.   * @return PropTreeItem
  7.   */
  8. function CreatePropTreeItem(str)
  9. {
  10. var params = ParseParams(str);
  11. var id = params['id'] || 'ERROR_NOT_DEFINED';
  12. if(id == 'ERROR_NOT_DEFINED')
  13. {
  14. return null;
  15. }
  16. var item = new PropTreeItem(id, params['pid'] || 0, parseInt(params['type']) || 0);
  17. for(key in params)
  18. {
  19. if(key != 'id' && key != 'pid' && key != 'type')
  20. {
  21.  
  22. item[key] = params[key];
  23. }
  24. }
  25. return item;
  26. }
  27.  
  28.  

Для создания дерева используется описанная ранее функция MFCCallMethod, а для управления свойствами таблицы – MFCSetAttrib. Вот так выглядит функция обработки команд приходящих с уровня JavaScript

  1.  
  2. void Cjs_proptreeDoc::HandleJSCommand(int cmd, CString param)
  3. {
  4. CString method = "";
  5. CString str = "";
  6.  
  7. switch(cmd)
  8. {
  9. case 1002: //Navigation of property tree view complete
  10.  
  11. method = "^obj^testTree^method^Add^value^";
  12. str = ":id:BORDER_STYLE:pid:BORDER:type:3:name:Стиль:value:solid";
  13. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  14.  
  15. method = "^obj^testTree.items['BORDER_STYLE']^method^SetCombo^value^";
  16. str = ":none:none:solid:solid:dotted:dotted:dashed:dashed";
  17. str += ":double:double:groove:groove:ridge:ridge:inset:inset:outset:outset";
  18. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  19.  
  20. method = "^obj^testTree^method^Add^value^";
  21.  
  22. str = ":id:TABLE_BGCOLOR:pid:COLORS:type:2:name:Цвет фона";
  23. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  24.  
  25. str = ":id:TABLE_HEAD:pid:ROOT:type:1:name:Заголовок:value:Таблица";
  26. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  27.  
  28. str = ":id:TABLE_COLOR:pid:COLORS:type:2:name:Цвет текста:value:black";
  29. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  30.  
  31. str = ":id:BORDER:pid:ROOT:name:Рамка";
  32. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  33.  
  34. str = ":id:BORDER_WIDTH:pid:BORDER:type:1:name:Ширина:value:1";
  35. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  36.  
  37. str = ":id:ROOT:name:Свойства таблицы:var:123.45";
  38. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  39.  
  40. str = ":id:COLORS:pid:ROOT:collapsed:true:name:Цвета";
  41. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  42.  
  43. str = ":id:BORDER_COLOR:pid:BORDER:type:2:name:Цвет:value:gray";
  44. m_treeView->CallJavaScript("MFCCallMethod", method + str);
  45.  
  46. m_treeView->CallJavaScript("MFCCallMethod", "^obj^testTree^method^FixLevels^value^8");
  47. m_treeView->CallJavaScript("MFCCallMethod", "^obj^testTree^method^Show^value^");
  48. break;
  49. default:
  50. str += ":obj:";
  51. str += m_treeView->GetParam("obj");
  52. str += ":attrib:";
  53. str += m_treeView->GetParam("attrib");
  54. str += ":value:";
  55. str += m_treeView->GetParam("value");
  56. m_mainView->CallJavaScript("MFCSetAttrib", str);
  57. break;
  58. }
  59. }
  60.  
  61.  

Скачать пример

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

P.S. Несколько слов о структуре проекта, а точнее о формировании HTML-документов.

Во вложенной папке html содержится файл refresh.bat, который осуществляет объединение нескольких файлов в один результирующий.

  1.  
  2. for %%i in (*.html) do (
  3. copy /b .\%%i+.\_jsstart.txt+.\_js.txt+.\_jsend.txt+.\%%i.end ..\%config%\%%i
  4. )
  5.  
  6.  

Стоит обратить внимание на то, что каждый html файл разбит на две части, например, script.html и script.html.end, первый из которых должен содержать весь HTML код, а второй – специфичные для этой страницы скрипты и вызовы функций, если это необходимо. Например, в файле script.html.end происходит вызов функции SendCommand(1002), которая нотифицирует уровень C++ о том, что загрузка этой страницы закончена и можно начинать формирование дерева свойств.

Данный порядок получения результирующих файлов был получен в результате продолжительной борьбы, во время которой CHtmlView периодически не мог найти некоторые скрипты или другие элементы страницы. Почему подобное происходит, для меня все еще остается загадкой, но часто проблемы с потерей объектов решаются путем перестановки кода.

Читайте в блоге

JavaScript Определение координат объектов и указателя мыши
JavaScript Property Tree. Реализация дерева свойств на JavaScript
Знакомство с WordPress
Создание таблиц в плагине для WordPress
JavaScript Преобразование массивов и объектов в строку

Комментарии:

Войдите на сайт, чтобы оставить комментарий