BEST logo логотип компании БЭСТ - программы для бизнеса ПРОДАЖИ
+7 (991) 312-04-37
trade@bestnet.ru
ПОДДЕРЖКА
+7 (495) 775-66-76
consult@bestnet.ru
СКАЧАТЬ
Обновления
Дистрибутивы
Авторизация

Логин:
Пароль:
Забыли свой пароль?
Регистрация
ВАШ ВОПРОС

Доступ к Личному кабинету закрыт!
Как получить доступ?


Форум

Поиск  Пользователи  Правила 
Закрыть
Логин:
Пароль:
Забыли свой пароль?
Регистрация
Войти
 
Страницы: 1
RSS
Проблема с GUI_COMBO, не обновляется выбранное значение в ComboBox
 
БЭСТ 3.4 СП 23.11, хозрасчет
Уважаемые разработчики и модераторы форума, просим Вашей помощи о решении следующей проблемы.
Пытаемся создать плагин с отображением собственной формы и графическими элементами, из реестра сотрудников в зарплате.
Существует следующий код:
Цитата
fMyForm:=GUI_FORMCREATE(,"Myform",0,0,350,600,,,,,)
fMyCombo:=GUI_COMBOCREATE(fMyForm,"MyCombo",10,10,300,15)
fMyLabel=GUI_LABELCREATE(fMyForm,"MyLabel",10,30,300,15)
GUI_COMBOSETITEMS(fMyCombo,aInouts,)
GUI_LABELTEXT(fMyLabel,"Введите процент:")
GUI_FORMSHOWMODAL(fMyForm)
i:=GUI_COMBOSETSELECTEDITEM(fMycombo,)

*aInOuts - двумерный массив значений

Проблема в том, что при выборе элемента в ComboBox, выбранное значение не обновляется в окне бокса, а остается старым (первое в списке), хотя в переменную i выбранное значение передается корректно.
Судя по всему необходимо обновить либо сам объект Combo, либо форму, но какой командой это сделать не понятно.
Будем благодарны за любую помощь.
 
На Ваш Вопрос будет дан ответ.
А у меня к Вам встречный Вопрос.
Вы в новых окнах пробовали такую форму сделать - почему именно через функции ?
 
Цитата
krssu пишет:
БЭСТ 3.4 СП 23.11, хозрасчет

Уважаемые разработчики и модераторы форума, просим Вашей помощи о решении следующей проблемы.

Пытаемся создать плагин с отображением собственной формы и графическими элементами, из реестра сотрудников в зарплате.

Существует следующий код:

Цитата
fMyForm:=GUI_FORMCREATE(,"Myform",0,0,350,600,,,,,)

fMyCombo:=GUI_COMBOCREATE(fMyForm,"MyCombo",10,10,300,15)

fMyLabel=GUI_LABELCREATE(fMyForm,"MyLabel",10,30,300,15)

GUI_COMBOSETITEMS(fMyCombo,aInouts,)

GUI_LABELTEXT(fMyLabel,"Введите процент:")

GUI_FORMSHOWMODAL(fMyForm)

i:=GUI_COMBOSETSELECTEDITEM(fMycombo,)


*aInOuts - двумерный массив значений



Проблема в том, что при выборе элемента в ComboBox, выбранное значение не обновляется в окне бокса, а остается старым (первое в списке), хотя в переменную i выбранное значение передается корректно.

Судя по всему необходимо обновить либо сам объект Combo, либо форму, но какой командой это сделать не понятно.
Будем благодарны за любую помощь.

Добрый день!
Странно, у нас работает то что здесь написано.
Посмотрели на СП23ХФ11.
Разве что узнать, что за значения в aInOuts
может что специфическое...
 
Цитата
nordk пишет:
Вы в новых окнах пробовали такую форму сделать - почему именно через функции?

Уважаемый nordk, в новых окнах эти функции отрабатывают, по крайней мере, в реестре приказов модуля кадры.
На некоторые консольные функции ругается, например на NOORYES, но мы так понимаем, нужно использовать только GUI-функции в данных окнах.
Что касается вызова формы через функции, то постараюсь объяснить суть задачи, а Вы посмотрите пожалуйста, каким способом лучше и проще реализовать, может подскажите интересную мысль. Такому специалисту, как Вы nordk, думаю это не составит большого труда.
Задача следующая:
В реестре лицевых счетов сотрудников модуля зарплаты, реализовать групповую функцию установки процента для выбранного начисления/удержания (Н/У).
Реализация: Отметка сотрудников в реестре; Вызов спецфункции (горячей клавишей); Отображение окна с элементами: ввод Н/У (выбор из справочника), ввод процента.
Сейчас функция практически написана и составляет порядка 30-40 строк кода. Осталось решить проблему с обновлением значения Combo и событиями мыши на модальные кнопки (Ок, Отмена).

Цитата
Александр Титов пишет:
Разве что узнать, что за значения в aInOuts может что специфическое...

Доброе утро, Александр, спасибо за уделенное время для разрешения вопросов!
Массив aInOuts двумерный, следующего вида {{"А"},{"B"},{"C"}}, в данном случае заполняется следующим образом из справочника Н/У:
aInOuts[i,1]:=inouts->code+"|"+inouts->name
т.е., "АВА|Аванс"
И ещё, Александр, будьте любезны ответить на несколько смежных вопросов, мы будем весьма благодарны за Вашу помощь.
1. По объектной модели, у каждого объекта есть события (onActivate, onClick и т.п.), как обратиться к данным событиям?
Пока используем событие на нажатие клавиш GUI_SETKEY(fMyButton,13,{||GUI_FORMCLOSE(fMyForm)})
Получается довольно криво, привязаться бы ещё к "мышиным" действиям, тогда было бы проще.
2. Вызываемая форма является модальной. А как правильно описать кнопки "Ок" и "Отмена", чтобы они закрывали форму и возвращали результат в программу? Что-то типа "mbOk" или "mbCancel", как это реализовано в дизайнере отчетов.
3. Обязательно ли использовать qInitPush и qInitPop при вызове таких форм?
Изменено: krssu - 01.03.2010 05:51:06
 
Цитата
krssu пишет:
Уважаемый nordk, в новых окнах эти функции отрабатывают, по крайней мере, в реестре приказов модуля кадры.
На некоторые консольные функции ругается, например на NOORYES, но мы так понимаем, нужно использовать только GUI-функции в данных окнах.


В новых окнах надо действительно использовать новые средства программирования.
Только писать их можно по-разному.
А именно, можно писать в редакторе ХВА и там для новых оконо мучаться с описанными Вами выше функциями, либо раскрыть BestIde и разрабатывать там плагин.
Там Вы иожете создавать свою форму, описыавть в инспекторе свойства всевозможные, которые Вам нужны и так далее. Идти этим же путем через описание внутри функций наверно не так удобно.

Цитата
krssu пишет:
В реестре лицевых счетов сотрудников модуля зарплаты

Модуль зарплата содан в так называемых "старых" окнах.
Если Вы сделаете диалоговую форму в BestIde, то я могу подсказать Вам как ее запустить из консольного окна.
Но там можно было делать и в старых принципах.
Я наверно по-быстрому подключил бы Dialog или средствами Qinput
Можно просто использовать Get
Ведь если я правильно понял - Вам нужна была диалоговая форма для ввода к Вашей задаче. В этом случае NoOrYes отработает.
Кстати обратите Внимание на MessageBox( <Text> , <Caption> , <Flags> )
 
Спасибо, nordk, за пояснения.
Реализовали ввод с помощью QInput, пришлось перелопатить весь форум, чтобы найти "нормальное" описание и пример, но это уже дело десятое.
Кстати, если не затруднит, подскажите пожалуйста, где можно найти нормальный пример с настройкой BestIde и созданием простой формы? Ведь на форуме много уроков, но только старые 2008 года, и все какие-то интересные: "Добавили код"-"Ошибка того"-"Исправили"-"Ошибка другого", не хватает четкой последовательности действий.
И ещё небольшой Вопрос: есть массив aIn, который, как понимаем, содержит имена полей. А как посмотреть его содержимое, в отладчике отсутствует?
Изменено: krssu - 02.03.2010 10:42:03
 
Цитата
krssu пишет:
Ведь на форуме много уроков

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

Цитата
krssu пишет:
QInput, пришлось перелопатить весь форум

Есть тема урок на старом форуме. Вы ее нашли ?

Цитата
krssu пишет:
массив aIn, который, как понимаем, содержит имена полей

aIn массив для Get-объектов.
Он не содержит имен полей, а только значения в той же последовательности как мы задали в aheads.
В отладчике этот массив виден, если например сделать точку останова при выполнении блока кода bPreGet или bScrInit
 
Спасибо, Константин (nordk), за грамотное разъяснение вопросов и уделенное время.
Цитата
nordk пишет:
Если что-то не получается - напишите прямо там в уроке пожалуйста и будем смотреть, как его надо улучшить.
Создание простой формы мы не делали, давайте сделаем и такой урок.

Было бы замечательно, если бы такой урок был, давайте сделаем его вместе, будем рады научиться.
Цитата
nordk пишет:
Есть тема урок на старом форуме. Вы ее нашли?

Да, тему посмотрели, собственно там большинство вопросов и разрешилось.
Цитата
nordk пишет:
...сделать точку останова при выполнении блока кода bPreGet или bScrInit

А у нас таких блоков нет.:(
Вот кусочек кода:
Цитата
inouts->(MakeRefer("saDT","Выбирите",2,{"Код","Наименование"},{2,5,10},,;
{FieldBlock("CODE")},{"aIn[2]"},"Upper(aIn[2])",{FieldBlock("CODE"),FieldBlock("NAME")}))
N_U:=' '
Prct:=00.00
aHeads :={{"Процент,%:","Prct","99.99"},{"Н/У......:","N_U"}}
Qinput(10,25,13,50,aHeads,1,{"Prct","SaDT"},,,,,,,,'RESTOFF')

Еще один маленький Вопрос, Константин, думаю ответить на него Вас не затруднит.
Как сделать массив aHeads из одного элемента?
Например: aHeads :={{"Н/У......:","N_U"}} ругается на переполнение массива.
Возможно использовать Qinput с одной переменной, в данном куске кода?
Изменено: krssu - 03.03.2010 11:22:07
 
Цитата
krssu пишет:
А у нас таких блоков нет.:(

Вы у себя не применяете, но в Qinput есть возможность использовать такие переменные
Посмотрите описание в хелпе данной функции

Цитата
krssu пишет:
FieldBlock("CODE")},{"

Вот это наследие с FileEval
Рекомендую писать прямо {||CODE} или даже правильнее {||field->CODE}

Цитата
krssu пишет:
aHeads :={{"Н/У......:","N_U"}}

Причин может быть несколько:
Во-первых у вас переменная N_U NIL а надо чтобы была хотябы SPACE(3)
По длине переменной строится длина вводимого значения
Во-вторых длина массива aHeads должнв совпадать с длиной массива aPict
В-третьих если вызов из БЭСТ-4, надо убедиться что есть активный текущий алиас и если нет - сделать какой-либо алиас активным.
 
Спасибо за уточнения и пояснения, Константин.
Теперь мы стали следовать Вашим рекомендациям и везде используем {||field->CODE}.
Почитав, внимательно, объяснение про массив aIn, поняли в чем заключалась ошибка; уменьшив массив aHeads до ввода одного значения, мы забыли уменьшить индекс массива в описании makerefer (ошибочно обращаясь к aIn[2]).
Позвольте ещё немного вопросов, Константин, если ещё Вам не надоело наше любопытство.
1. Подскажите пожалуйста, к какому объекту или свойству обращаться, если вызываешь спецфункцию в новых окнах?
Например: Кадры - Картотека сотрудников; Отметили нескольких сотрудников, Запустили спецфункцию.
В каком массиве хранятся данные о выбранных? В зарплате за это отвечает массив aTnums, в кадрах, так понимаем сложнее, в отладчике очень много классов форм и массивов.
2. Как в БЭСТе 3.4 работать с классом XMLDOC и классом XMLNode
Почитали здесь Экспорт-импорт в XML в спецфункциях, но всё так туманно. Нет ли простого примера для реализации?
 
Цитата
krssu пишет:
Подскажите пожалуйста, к какому объекту или свойству обращаться, если вызываешь спецфункцию в новых окнах?
Например: Кадры - Картотека сотрудников; Отметили нескольких сотрудников, Запустили спецфункцию.


В БЭСТе с отмеченными записями логика работы была такая:
1.Пишем плагин для обработки данных по строке
2.Отмечаем несколько строк
3.Запускаем плагин по требованию.

Он сам выполняется по каждой отмеченной строке.
Необходимости иметь доступ к массиву отмеченных строк нет
 
Цитата
krssu пишет:
Как в БЭСТе 3.4 работать с классом XMLDOC и классом XMLNode
Почитали здесь Экспорт-импорт в XML в спецфункциях, но всё так туманно. Нет ли простого примера для реализации?


Описание классов

Код
/*
 *  CLASS DEFINITION
 *  HXMLDoc
 */

CLASS HXMLDoc INHERIT HXMLNode

   METHOD New( encoding )
   METHOD Read( fname )
   METHOD ReadString( buffer )  INLINE ::Read( ,buffer )
   METHOD Save( fname,lNoHeader )
   METHOD Save2String()  INLINE ::Save()
ENDCLASS


Код
/*
 *  CLASS DEFINITION
 *  HXMLNode
 */

CLASS HXMLNode

   DATA title
   DATA type
   DATA aItems  INIT {}
   DATA aAttr   INIT {}

   METHOD New( cTitle, type, aAttr )
   METHOD Add( xItem )
   METHOD GetAttribute( cName )
   METHOD SetAttribute( cName,cValue )
   METHOD Save( handle,level )
   METHOD Find( cTitle,nStart )
ENDCLASS


Часть кода из БЭСТ-5

Код
FUNCTION ObjToXml(o,oXml,cName)
LOCAL x,nScope
LOCAL aList:= IF(VALTYPE(o)=="A",o,__ObjGetValueList( o,{"PARENT"},EXPORTED:))
LOCAL oXmlNode
IF EMPTY(cName)
   cName:=o:Classname()
ENDIF
IF oXml==NIL
   oXml:= HXMLDoc():New("windows-1251")
ENDIF
oXmlNode:=oXml:Add(HXMLNode():New(cName))
//altd()
FOR EACH x IN aList
IF VALTYPE(x)="O"
   ObjToXml(x,oXmlNode)
ELSEIF VALTYPE(x[2])="A"
   ObjToXml(x[2],oXmlNode,x[1])
ELSE
   AADD(oXmlNode:AATTR,x)
ENDIF
NEXT

RETURN oXml
 
Спасибо, за столь скорый ответ, Константин.
Цитата
nordk пишет:
Он сам выполняется по каждой отмеченной строке. Необходимости иметь доступ к массиву отмеченных строк нет.

Что по каждой строке выполняется, это понятно. Вопрос в том, как получить выбранное значение, например табельный номер или ID, из формы?

Вопрос по классу XMLDOC, вот простой пример:
Код
oDoc := HXMLDoc():New("windows-1251")
oNode:= HXMLNode():New("Перечни",,{{"ВерсияФормата","1.7"}})
oNode2:=HXMLNode():New("Перечень",,{{"ДатаЗаполнения","2009"}})
oDoc:Add(oNode)
oDoc:aItems[1]:Add(oNode2)
oDoc:aItems[1]:Add(oNode2)
oDoc:aItems[1]:aItems[1]:SetAttribute("ДатаЗаполнения","1999")
FErase("c:\manifest.xml") 
oDoc:Save("c:\manifest.xml")

Как сменить кодировку с UTF на 1251?
//Уже не нужно, понял по куску предоставленного Вами кода: HXMLDoc():New("windows-1251")
Как реализовать сдвиг вправо, написано xRight, но он не работает?
И как вообще не плодить объекты Node (oNode1, oNode2), а обращаться к ним по имени?
И вот ещё проблема при таком коде:
Код
oDoc:aItems[1]:aItems[1]:SetAttribute("ДатаЗаполнения","1999")

Попытка изменить у одного из Нодов атрибут, приводит к смене атрибута у всех аналогичных Нодов.
Чтобы файл был в таком виде:
Код
<?xml version="1.0" encoding="windows-1251"?>
<ПеречниЛьготныхПрофессий ВерсияФормата="1.7">
  <Перечень ДатаЗаполнения="2009">
  </Перечень>
  <Перечень ДатаЗаполнения="1999">
  </Перечень>
</ПеречниЛьготныхПрофессий>

И ещё Вопрос по QInput:
В зарплате в лицевом счете, при вводе Н/У можно пробелом выбирать "Начисление" или "Удержание", в зависимости от этого отображаются в следующем поле только начисления или только удержания.
Как реализовать такое в своем QInput?
Константин, а Вы бы могли пообщаться cо мной по ICQ?
Изменено: krssu - 09.03.2010 11:38:29
 
Цитата
krssu пишет:
В зарплате в лицевом счете, при вводе Н/У можно пробелом выбирать "Начисление" или "Удержание", в зависимости от этого отображаются в следующем поле только начисления или только удержания.
Как реализовать такое в своем QInput?

На старом форуме есть пример организации справочника на клавишу пробел.

Цитата
krssu пишет:
Константин, а Вы бы могли пообщаться cо мной по ICQ (571-998-157)?

Мне удобнее писать когда есть такая возможность.
И потом правильнее через форум, пусть будут ответы для тех, кто потом будет искать.
 
Цитата
nordk пишет:
Что по каждой строке выполняется, это понятно. в том, как получить выбранное значение, например табельный номер или ID, из формы?

Плагин идет по строчкам - встал на строку - прочитали из нее тадельный номер в свою переменную или в aGLobVars
 
Уважаемый Константин, спасибо за пояснения.
Цитата
nordk пишет:
Плагин идет по строчкам - встал на строку - прочитали из нее табельный номер в свою переменную или в aGLobVars

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

Указанный выше код по смене атрибута не работает, исправил на такой кусок, заработало:
Код
oDoc := HXMLDoc():New("windows-1251") 
oDoc:Add(HXMLNode():New("Перечни",,{{"ВерсияФормата","1.7"}})) 
oDoc:aItems[1]:Add(HXMLNode():New("Перечень",,{{"ДатаЗаполнения","2009"}})) 
oDoc:aItems[1]:Add(HXMLNode():New("Перечень",,{{"ДатаЗаполнения","1999"}})) 
oDoc:aItems[1]:aItems[2]:SetAttribute("ДатаЗаполнения","1888")

Может быть причина в наследовании свойств объектов oNode? Или в чем то другом.
 
Ещё небольшой Вопрос, Константин, про "пробел". На старом форуме нашли тему, но связки со справочником не получается.
Код
        N_U:=SPACE(3)
        Prct:=00.00
        T_1:=SPACE(1)
        aPict:={REPLICATE('X',10),REPLICATE('X',3),"99.99"}
        aHeads :={{"Выберите сортировку:","T_1"},{"Н/У......:","N_U"},{"Процент:","Prct","99.99"}} 
        aType:={{'+','Начисления'}, ;
                {'-','Удержания '}}
        aRef:={{|x|RotateAndReader(x,aType)},"SaDT","Prct"}
        aGetBlock:={{|x|RotateBlock(x,aType,"aIn[1]")}}
        inouts->(MakeRefer("saDT","Выберите",1,{"Код","Наименование"},{2,5,10},,;
                 {"CODE"},{"aIn[2]"},"Upper(aIn[2])",{{||Field->CODE},{||Field->NAME}}))
        Qinput(10,25,14,48,aHeads,1,aRef,aPict,,,,,,,'REFER',aGetBlock)

Как теперь выбранное значение aType привязать к индексу?
Спасибо, самостоятельно решили с помощью тем старого форума, там очень много Ваших советов.
Вот такой получился код:
Код
      //переменные
      N_U:=SPACE(3)
      Prct:=00.00
      T_1:=SPACE(1)
      //массив масок ввода
      aPict:={REPLICATE('X',10),REPLICATE('X',3),"99.99"}
      //массив заголовков и переменных ввода 
      aHeads :={{"Введите:","T_1"},{"Н/У......:","N_U"},{"Процент,%:","Prct","99.99"}}
      //массив для выбора "пробелом" значений
      aType:={{'+','Начисления'},{'-','Удержания '}}
      //массив имен справочников или переменных
      aRef:={{|x|RotateAndReader(x,aType)},"SaDT","Prct"}
      //массив блоков считывания в переменные
      aGetBlock:={{|x|RotateBlock(x,aType,"aIn[1]")}}
      //создаем справочник
      inouts->(MakeRefer("saDT","Выберите",1,{"Код","Наименование"},{2,5,10},,;
               {"CODE"},{"aIn[2]"},"Upper(aIn[2])",{{||Field->CODE},{||Field->NAME}},,,,,,,;
               {||IF(aIn[1]="+",inouts->(OrdSetfocus(1)),inouts->(OrdSetfocus(4)))}))
      //выводим окно
      Qinput(10,25,14,48,aHeads,1,aRef,aPict,,,,,,,'REFER',aGetBlock)

Константин, посмотрите пожалуйста, всё ли мы сделали правильно?
Изменено: krssu - 10.03.2010 09:14:51
 
Да вроде нормально.
 
Огромное спасибо, Константин, всё получилось благодаря Вам.
 
Вот кусок из rtl.bdll, объекта TXMLNode:
Код
TXMLNODE NEW A HBCLASS  __CLS_PARAM  ADDMULTIDATA A ADDMETHOD A TXMLNODE_NEW ADDINLINE A HBXML_NODE_CLONE  HBXML_NODE_CLONE_TREE  HBXML_NODE_UNLINK  TXMLNODE_NEXTINTREE HBXML_NODE_INSERT_BEFORE  HBXML_NODE_INSERT_AFTER  HBXML_NODE_INSERT_BELOW  HBXML_NODE_ADD_BELOW  AATTRIBUTES A TXMLNODE_DEPTH TXMLNODE_PATH HBXML_NODE_TO_STRING  HBXML_NODE_WRITE  NTYPE A CNAME A CDATA A CREATE A HCLASS A __CLSINST  PCOUNT  CONSTRUCTORCALL A HB_APARAMS  _NTYPE A _AATTRIBUTES A HASH  _CNAME A _CDATA A OCHILD A ONEXT A OPARENT A DEPTH A PATH A TXMLITERATOR ATXMLITERATOR_NEW TXMLITERATOR_NEXT _ONODE A OTOP A TXMLITERATOR_FIND ONODE A TXMLITERATOR_SETCONTEXT TXMLITERATOR_CLONE TXMLITERATOR_MATCHCRITERIA _OTOP A _NTOPLEVEL A ONODETOP A _CATTRIBUTE A CATTRIBUTE A _CVALUE A CVALUE A MATCHCRITERIA A NEXT A NEXTINTREE A NTOPLEVEL A TXMLITERATORSCAN TXMLITERATORSCAN_NEW TXMLITERATORSCAN_MATCHCRITERIA HSCAN  TXMLITERATORREGEX TXMLITERATORREGEX_NEW TXMLITERATORREGEX_MATCHCRITERIA TXMLDOCUMENT TXMLDOCUMENT_NEW HBXML_DATAREAD  TOSTRING A OROOT A WRITE A TXMLDOCUMENT_FINDFIRST TXMLDOCUMENT_FINDFIRSTREGEX OITERATOR A TXMLDOCUMENT_GETCONTEXT _NSTATUS A _NERROR A _NLINE A _NNODECOUNT A _OROOT A VALTYPE  READ A _OITERATOR A FIND A GETNODE A XMLDOCOPENSTRING XMLDOCGETROOTTAG XMLGETTAG AADD  LEN  HGETKEYAT  HGETVALUEAT  (_INITSTATICS)    TXMLNODE

Содержит столько методов и функций использования XML-объекта, это полноценный объект или описание HXMLNode? Как его можно использовать?
 
Цитата
krssu пишет:
Вот кусок из rtl.bdll, объекта TXMLNode:
TXMLNODE NEW A HBCLASS __CLS_PARAM ADDMULTIDATA A ADDMETHOD A TXMLNODE_NEW ADDINLINE A HBXML_NODE_CLONE HBXML_NODE_CLONE_TREE HBXML_NOD ­E_UNLINK TXMLNODE_NEXTINTREE

Добрый день!
Так очень трудоемко :-)
Мы всегда готовы поделиться исходниками (особенно с большим удовольствием для тех кто в этом понимает):

Код
#include "hbclass.ch"
#include "fileio.ch"
#include "hxml.ch"

#DEFINE  CRLF CHR(13)+CHR(10)


/*
 *  CLASS DEFINITION
 *  HXMLNode
 */

CLASS HXMLNode

   DATA title
   DATA type
   DATA aItems  INIT {}
   DATA aAttr   INIT {}

   METHOD New( cTitle, type, aAttr )
   METHOD Add( xItem )
   METHOD GetAttribute( cName )
   METHOD SetAttribute( cName,cValue )
   METHOD Save( handle,level )
   METHOD Find( cTitle,nStart )
ENDCLASS

METHOD New( cTitle, type, aAttr, cValue ) CLASS HXMLNode

   IF cTitle != Nil ; ::title := cTitle ; ENDIF
   IF aAttr  != Nil ; ::aAttr := aAttr  ; ENDIF
   ::type := Iif( type != Nil , type, HBXML_TYPE_TAG )
   IF cValue != Nil
      ::Add( cValue )
   ENDIF
Return Self

METHOD Add( xItem ) CLASS HXMLNode

   Aadd( ::aItems, xItem )
Return xItem

METHOD GetAttribute( cName ) CLASS HXMLNode
Local i := Ascan( ::aAttr,{|a|a[1]==cName} )

Return Iif( i==0, Nil, ::aAttr[ i,2 ] )

METHOD SetAttribute( cName,cValue ) CLASS HXMLNode
Local i := Ascan( ::aAttr,{|a|a[1]==cName} )

   IF i == 0
      Aadd( ::aAttr,{ cName,cValue } )
   ELSE
      ::aAttr[ i,2 ] := cValue
   ENDIF

Return .T.

METHOD Save( handle,level ) CLASS HXMLNode
Local i, s, lNewLine

   s := Space(level*2) + '<'
   IF ::type == HBXML_TYPE_COMMENT
      s += '!--'
   ELSEIF ::type == HBXML_TYPE_CDATA
      s += '![CDATA['
   ELSEIF ::type == HBXML_TYPE_PI
      s += '?' + ::title
   ELSE
      s += ::title
   ENDIF
   IF ::type == HBXML_TYPE_TAG .OR. ::type == HBXML_TYPE_SINGLE
      FOR i := 1 TO Len( ::aAttr )
         s += ' ' + ::aAttr[i,1] + '="' + HBXML_Transform1(::aAttr[i,2]) + '"'
      NEXT
   ENDIF
   IF ::type == HBXML_TYPE_COMMENT
      s += '-->' + CRLF
   ELSEIF ::type == HBXML_TYPE_PI
      s += '?>' + CRLF
   ELSEIF ::type == HBXML_TYPE_SINGLE
      s += '/>' + CRLF
   ELSEIF ::type == HBXML_TYPE_TAG
      s += '>'
      IF Len(::aItems) == 1 .AND. Valtype(::aItems[1]) == "C" .AND. ;
                Len(::aItems[1]) + Len(s) < 1000
         lNewLine := .F.
      ELSE
         s += CRLF
         lNewLine := .T.
      ENDIF
   ENDIF
   IF handle >= 0
      FWrite( handle,s )
   ENDIF

   FOR i := 1 TO Len( ::aItems )
      IF Valtype( ::aItems[i] ) == "C"
        IF handle >= 0
           IF ::type == HBXML_TYPE_CDATA
              FWrite( handle, ::aItems[i] )
           ELSE
              FWrite( handle, HBXML_Transform1( ::aItems[i] ) )
           ENDIF
        ELSE
           IF ::type == HBXML_TYPE_CDATA
              s += ::aItems[i]
           ELSE
              s += HBXML_Transform1( ::aItems[i] )
           ENDIF
        ENDIF
      ELSE
        s += ::aItems[i]:Save( handle, level+1 )
      ENDIF
   NEXT
   IF handle >= 0
      IF ::type == HBXML_TYPE_TAG
         FWrite( handle, Iif(lNewLine,Space(level*2),"") + '</' + ::title + '>' + CRLF )
      ELSEIF ::type == HBXML_TYPE_CDATA
         FWrite( handle, ']]>' + CRLF )
      ENDIF
   ELSE
      IF ::type == HBXML_TYPE_TAG
         s += Iif(lNewLine,Space(level*2),"") + '</' + ::title + '>' + CRLF
      ELSEIF ::type == HBXML_TYPE_CDATA
         s += ']]>' + CRLF
      ENDIF
      Return s
   ENDIF
Return ""

METHOD Find( cTitle,nStart,block ) CLASS HXMLNode
Local i

   IF nStart == Nil
      nStart := 1
   ENDIF
   DO WHILE .T.
      i := Ascan( ::aItems,{|a|Valtype(a)!="C".AND.a:title==cTitle},nStart )
      IF i == 0
         EXIT
      ELSE
         nStart := i
         IF block == Nil .OR. Eval( block,::aItems[i] )
            Return ::aItems[i]
         ELSE
            nStart ++
         ENDIF
      ENDIF
   ENDDO

Return Nil


/*
 *  CLASS DEFINITION
 *  HXMLDoc
 */

CLASS HXMLDoc INHERIT HXMLNode

   METHOD New( encoding )
   METHOD Read( fname )
   METHOD ReadString( buffer )  INLINE ::Read( ,buffer )
   METHOD Save( fname,lNoHeader )
   METHOD Save2String()  INLINE ::Save()
ENDCLASS

METHOD New( encoding ) CLASS HXMLDoc

   IF encoding != Nil
      Aadd( ::aAttr, { "version","1.0" } )
      Aadd( ::aAttr, { "encoding",encoding } )
   ENDIF

Return Self

METHOD Read( fname,buffer ) CLASS HXMLDoc
Local han

   IF fname != Nil
      han := FOpen( fname, FO_READ )
      IF han != -1
         hbxml_GetDoc( Self,han )
         FClose( han )
      ENDIF
   ELSEIF buffer != Nil
      hbxml_GetDoc( Self,buffer )
   ELSE
      Return Nil
   ENDIF
Return Self

METHOD Save( fname,lNoHeader ) CLASS HXMLDoc
Local handle := -2
Local cEncod, i, s

   IF fname != Nil
      handle := FCreate( fname )
   ENDIF
   IF handle != -1
      IF lNoHeader == Nil .OR. !lNoHeader
         IF ( cEncod := ::GetAttribute( "encoding" ) ) == Nil
            cEncod := "UTF-8"
         ENDIF
         s := '<?xml version="1.0" encoding="'+cEncod+'"?>'+CRLF
         IF fname != Nil
            FWrite( handle, s )
         ENDIF
      ELSE
         s := ""
      ENDIF
      FOR i := 1 TO Len( ::aItems )
         s += ::aItems[i]:Save( handle, 0 )
      NEXT
      IF fname != Nil
         FClose( handle )
      ELSE
         Return s
      ENDIF
   ELSE
      MessageBox("Не могу записать файл "+fname)
   ENDIF
Return .T.


FUNCTION CutExten( fname )

LOCAL i
RETURN IIF( ( i := RAT( '.', fname ) ) = 0, fname, SUBSTR( fname, 1, i - 1 ) )

FUNCTION FilExten( fname )

LOCAL i
RETURN IIF( ( i := RAT( '.', fname ) ) = 0, "", SUBSTR( fname, i + 1 ) )

FUNCTION FilePath( fname )
LOCAL i
RETURN IIF( ( i := RAT( '\', fname ) ) = 0, ;
           IIF( ( i := RAT( '/', fname ) ) = 0, "", LEFT( fname, i ) ), ;
           LEFT( fname, i ) )


FUNCTION CutPath( fname )
LOCAL i
RETURN IIF( ( i := RAT( '\', fname ) ) = 0, ;
           IIF( ( i := RAT( '/', fname ) ) = 0, fname, SUBSTR( fname, i+1 ) ), ;
           SUBSTR( fname, i+1 ) )


STATIC FUNCTION HBXML_Transform1(x)
IF VALTYPE(x)=="C"
   IF EMPTY(x)
      x:=SPACE(1)
   ENDIF
ELSEIF x==NIL
   x:=""
ELSEIF VALTYPE(x)=="N"
   x:=ALLTRIM(STR(x))
ELSEIF VALTYPE(x)=="D"
   x:=DTOS(x)
ELSEIF VALTYPE(x)=="L"
   x:=IF(x,"T","F")
ENDIF
RETURN HBXML_Transform(x)




[/CODE]
 
Спасибо, Александр, теперь разбираться будет проще!
Страницы: 1
Читают тему (гостей: 1)