БЭСТ 3.4 СП 23.11, хозрасчет
Уважаемые разработчики и модераторы форума, просим Вашей помощи о решении следующей проблемы.
Пытаемся создать плагин с отображением собственной формы и графическими элементами, из реестра сотрудников в зарплате.
Существует следующий код:
Проблема в том, что при выборе элемента в ComboBox, выбранное значение не обновляется в окне бокса, а остается старым (первое в списке), хотя в переменную i выбранное значение передается корректно.
Судя по всему необходимо обновить либо сам объект Combo, либо форму, но какой командой это сделать не понятно.
Будем благодарны за любую помощь.
Проблема в том, что при выборе элемента в 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 пишет:
Уважаемый nordk, в новых окнах эти функции отрабатывают, по крайней мере, в реестре приказов модуля кадры.
На некоторые консольные функции ругается, например на NOORYES, но мы так понимаем, нужно использовать только GUI-функции в данных окнах.
В новых окнах надо действительно использовать новые средства программирования.
Только писать их можно по-разному.
А именно, можно писать в редакторе ХВА и там для новых оконо мучаться с описанными Вами выше функциями, либо раскрыть BestIde и разрабатывать там плагин.
Там Вы иожете создавать свою форму, описыавть в инспекторе свойства всевозможные, которые Вам нужны и так далее. Идти этим же путем через описание внутри функций наверно не так удобно.
Цитата
krssu пишет:
В реестре лицевых счетов сотрудников модуля зарплаты
Модуль зарплата содан в так называемых "старых" окнах.
Если Вы сделаете диалоговую форму в BestIde, то я могу подсказать Вам как ее запустить из консольного окна.
Но там можно было делать и в старых принципах.
Я наверно по-быстрому подключил бы Dialog или средствами Qinput
Можно просто использовать Get
Ведь если я правильно понял - Вам нужна была диалоговая форма для ввода к Вашей задаче. В этом случае NoOrYes отработает.
Кстати обратите на MessageBox( <Text> , <Caption> , <Flags> )
Спасибо, nordk, за пояснения.
Реализовали ввод с помощью QInput, пришлось перелопатить весь форум, чтобы найти "нормальное" описание и пример, но это уже дело десятое.
Кстати, если не затруднит, подскажите пожалуйста, где можно найти нормальный пример с настройкой BestIde и созданием простой формы? Ведь на форуме много уроков, но только старые 2008 года, и все какие-то интересные: "Добавили код"-"Ошибка того"-"Исправили"-"Ошибка другого", не хватает четкой последовательности действий.
И ещё небольшой : есть массив aIn, который, как понимаем, содержит имена полей. А как посмотреть его содержимое, в отладчике отсутствует?
Вообще-то уроки рабочие наданном форуме и демонстрируют создание простого грида.
Но общая работа с BestIde вроде как должна получиться.
Если что-то не получается - напишите прямо там в уроке пожалуйста и будем смотреть, как его надо улучшить.
Создание простой формы мы не делали, давайте сделаем и такой урок.
Цитата
krssu пишет:
QInput, пришлось перелопатить весь форум
Есть тема урок на старом форуме. Вы ее нашли ?
Цитата
krssu пишет:
массив aIn, который, как понимаем, содержит имена полей
aIn массив для Get-объектов.
Он не содержит имен полей, а только значения в той же последовательности как мы задали в aheads.
В отладчике этот массив виден, если например сделать точку останова при выполнении блока кода bPreGet или bScrInit
Спасибо, Константин (nordk), за грамотное разъяснение вопросов и уделенное время.
Цитата
nordk пишет:
Если что-то не получается - напишите прямо там в уроке пожалуйста и будем смотреть, как его надо улучшить.
Создание простой формы мы не делали, давайте сделаем и такой урок.
Было бы замечательно, если бы такой урок был, давайте сделаем его вместе, будем рады научиться.
Цитата
nordk пишет:
Есть тема урок на старом форуме. Вы ее нашли?
Да, тему посмотрели, собственно там большинство вопросов и разрешилось.
Цитата
nordk пишет:
...сделать точку останова при выполнении блока кода bPreGet или bScrInit
Еще один маленький , Константин, думаю ответить на него Вас не затруднит.
Как сделать массив aHeads из одного элемента?
Например: aHeads :={{"Н/У......:","N_U"}} ругается на переполнение массива.
Возможно использовать Qinput с одной переменной, в данном куске кода?
Вы у себя не применяете, но в 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
* 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
Как сменить кодировку с UTF на 1251? //Уже не нужно, понял по куску предоставленного Вами кода: HXMLDoc():New("windows-1251")
Как реализовать сдвиг вправо, написано xRight, но он не работает?
И как вообще не плодить объекты Node (oNode1, oNode2), а обращаться к ним по имени?
И вот ещё проблема при таком коде:
И ещё по QInput:
В зарплате в лицевом счете, при вводе Н/У можно пробелом выбирать "Начисление" или "Удержание", в зависимости от этого отображаются в следующем поле только начисления или только удержания.
Как реализовать такое в своем QInput?
Константин, а Вы бы могли пообщаться cо мной по ICQ?
krssu пишет:
В зарплате в лицевом счете, при вводе Н/У можно пробелом выбирать "Начисление" или "Удержание", в зависимости от этого отображаются в следующем поле только начисления или только удержания.
Как реализовать такое в своем QInput?
На старом форуме есть пример организации справочника на клавишу пробел.
Цитата
krssu пишет:
Константин, а Вы бы могли пообщаться cо мной по ICQ (571-998-157)?
Мне удобнее писать когда есть такая возможность.
И потом правильнее через форум, пусть будут ответы для тех, кто потом будет искать.
nordk пишет:
Плагин идет по строчкам - встал на строку - прочитали из нее табельный номер в свою переменную или в aGLobVars
Принципы отработки плагина уже усвоили, благодаря Вашим объяснениям. Просто хотелось уточнить, может Вы знаете, какие-либо "хитрые" глобальные переменные, в которых хранятся выбранные сотрудники. Иногда, вместо объявлений своих переменных, достаточно использовать готовые, как в зарплате например, а так, будем продолжать брать данные из текущего алиаса.
Указанный выше код по смене атрибута не работает, исправил на такой кусок, заработало:
Как теперь выбранное значение aType привязать к индексу? Спасибо, самостоятельно решили с помощью тем старого форума, там очень много Ваших советов.
Вот такой получился код:
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)