Готовится к опубликованию новая сборка №48, которая выйдет в конце недели. Если у Вас есть интересные наработки для включения в новый релиз, то сейчас самое удобное время для их отправки мне
Кратко, что нового:
- исправление обнаруженных ошибок и неточностей кода; - новый класс HEADERIMAGE для Grid и Browse; - свойство Address в Hyperlink может теперь открывать папку или файл на диске; - добавлен NOTABSTOP класс для Browse; - поддержка пользовательских компонентов (заимствована из оффициального релиза); - расширения и исправления в библиотеках TsBrowse и PropGrid; - обновлены сборки Харбор и HMGS-IDE; - новые и обновленные старые примеры (как обычно ).
Отправлено: 16.06.17 09:19. Заголовок: gfilatov2002 Класс ..
gfilatov2002 Класс TKeyData в целом готов, выложу, для анализа и предложений сейчас Скрытый текст
/* * Создание объекта класса TKeyData, если задан параметр Obj, то в блоки кода * метода Do(...) передается значение Obj, иначе Self. */ *-----------------------------------------------------------------------------* FUNCTION oKeyData( Obj ) *-----------------------------------------------------------------------------* RETURN TKeyData():New(Obj)
////////////////////////////////////////////////////////////////////////////////////////////// CLASS TKeyData //////////////////////////////////////////////////////////////////////////////////////////////
/* * Выполнение блока кода Block над всеми элементами контейнера данных ::aKey. * Кодоблоку передаются ключ, значение и индекс. * Если параметр Block, не блок кода, возвращается массив значений, где * каждый элемент массив { ключ, значение, индекс } * Примеры использования в классе TWndData: * METHOD GetListType() * METHOD GetObj4Type( cType, lEque ) * METHOD GetObj4Name( cName ) */ METHOD Eval( Block ) CLASS TKeyData LOCAL i, b := HB_ISBLOCK(Block) LOCAL a := iif( b, Nil, array(0) )
For i := 1 To ::Len If b; Eval( Block, hb_HKeyAt( ::aKey, i ), hb_HValueAt( ::aKey, i ), i ) Else; aAdd( a, { hb_HKeyAt( ::aKey, i ), hb_HValueAt( ::aKey, i ), i } ) EndIf Next
RETURN a
/* * Выполнение операции суммирования над элементом контейнера данных с ключем Key. * xSum может быть числом или массивом, тогда суммируются только числовые элементы. * В качестве ключа можно использовать имена контролов, тогда возникает связка, при * событийном программировании, с событием заполнения Value контрола из контейнера. * Пример: Local o := oKeyData() * Local Als := oBrw1:cAlias * o:Sum("PRIHOD", { 0, 0, 0 }) * o:Sum("RASHOD", { 0, 0, 0 }) * DO WHILE ! Eof() * o:Sum("COUNT" , 1) * o:Sum("KOLVO" , (Als)->KOLVO) * o:Sum("SUMMA" , (Als)->SUMMA) * If (Als)->OPER == "PRI" * o:Sum("PRIHOD", { 1, (Als)->KOL_PRI, (Als)->SUM_PRI }) * ElseIf (Als)->OPER == "RAS" * o:Sum("RASHOD", { 1, (Als)->KOL_RAS, (Als)->SUM_RAS }) * EndIf * SKIP * ENDDO * ? o:Get("COUNT"), o:Get("KOLVO"), o:Get("SUMMA") * ? hb_valtoexp(o:Get("PRIHOD")) * ? hb_valtoexp(o:Get("RASHOD")) */ METHOD Sum( Key, xSum ) CLASS TKeyData
LOCAL sum := ::Get( Key, 0 )
If HB_ISNUMERIC( xSum ) If HB_ISNUMERIC( sum ); sum += xSum Else ; sum := xSum EndIf ::Put( Key, sum ) ElseIf HB_ISARRAY( xSum ) If HB_ISARRAY(sum) .and. Len(sum) == Len(xSum) AEval(xSum, {|s,i| sum[ i ]:= iif( HB_ISNUMERIC( s ), sum[ i ] + s, s ) } ) Else sum := xSum EndIf ::Put( Key, sum ) EndIf
RETURN Nil
/* * Освобождение собственных переменных объекта, устанавливаем в Nil. */ METHOD Destroy() CLASS TKeyData
LOCAL i, k, o
If HB_ISHASH( ::aKey ) For i := 1 To Len( ::aKey ) k := hb_HKeyAt( ::aKey, i ) hb_HSet( ::aKey, k, Nil ) hb_HDel( ::aKey, k ) Next EndIf
If HB_ISOBJECT(::Cargo) .and. ::Cargo:ClassName == ::ClassName o := ::Cargo If HB_ISHASH( o:aKey ) For i := 1 To Len( o:aKey ) k := hb_HKeyAt( o:aKey, i ) hb_HSet( o:aKey, k, Nil ) hb_HDel( o:aKey, k ) Next EndIf EndIf
::oObj := ::aKey := ::Cargo := Nil
RETURN Nil
SergKis
постоянный участник
Пост N: 1543
Зарегистрирован: 17.02.12
Отправлено: 16.06.17 09:22. Заголовок: PS _METHOD ... это у..
PS _METHOD ... это у меня #define _METHOD METHOD что бы не дублировались объявления с реальными методами при работе с проектом - список Entyti на экране
SergKis
постоянный участник
Пост N: 1544
Зарегистрирован: 17.02.12
Отправлено: 16.06.17 09:28. Заголовок: Петр Спасибо за DEST..
Петр Спасибо за DESTRUCTORв hb, работает.
SergKis
постоянный участник
Пост N: 1545
Зарегистрирован: 17.02.12
Отправлено: 16.06.17 13:01. Заголовок: SergKis пишет * П..
то повесив в new версии эту ф-ю на APPEVENT от Петра, можно в блоке кода скинуть, полученные итоги на контролы, которым были даны имена ключей (в блоке можем сделать):
FUNC ToItog( o, cH, cM, cO ) ? o:ClassName, cH, cM, cO ? o:Get("COUNT"), o:Get("KOLVO"), o:Get("SUMMA") ? hb_valtoexp(o:Get("PRIHOD")) ? hb_valtoexp(o:Get("RASHOD")) _SetValue('COUNT', 'win_1', cValToChar(o:Get("COUNT"))) ...
SergKis
постоянный участник
Пост N: 1546
Зарегистрирован: 17.02.12
Отправлено: 16.06.17 13:32. Заголовок: PS в ToItog можно и ..
PS в ToItog можно и так вывести данные на контролы
цитата:
AEval(o:Eval(), {|ky,uv,ni| win_1.&(ky).Value := cValToChar(uv), ni := ky })
Кому интересно. Выкладываю классы для vm и vmmt режимов hb. Скрытый текст
*-----------------------------------------------------------------------------* FUNCTION oWndData( nIndex, cName, nHandle, nParent, cType, cVar, oWin, lVmMt ) *-----------------------------------------------------------------------------* LOCAL o
If ! HB_ISOBJECT( oWin ) // window o := TWndData():New():Def( nIndex, cName, nHandle, nParent, cType, cVar, lVmMt ) Else // control o := TCnlData():New():Def( nIndex, cName, nHandle, nParent, cType, cVar, oWin, lVmMt ) If ! Empty(o:Name) .and. ! Empty(o:Handle) If o:Type == 'TBROWSE' o:TBrowse := _HMG_aControlIds [ o:Index ] EndIf o:Set() EndIf EndIf
RETURN o
/////////////////////////////////////////////////////////////////////////////// CLASS TWndData ///////////////////////////////////////////////////////////////////////////////
PROTECTED: VAR cVar VAR cName VAR cType VAR nIndex VAR nHandle VAR nParent VAR cChr INIT ',' VAR lMT INIT .F.
METHOD AddMethod( cMethod, pFunct ) CLASS TWndData
LOCAL o := Self
If HB_ISCHAR( cMethod ) .and. ! __ObjHasMsg( o, cMethod ) RETURN ! Empty( __objAddMethod( o, cMethod, pFunct ) ) ENDIF
RETURN .F.
METHOD DelMethod( cMethod ) CLASS TWndData
LOCAL o := Self
If HB_ISCHAR( cMethod ) .and. __ObjHasMsg( o, cMethod ) RETURN Empty( __objDelMethod( o, cMethod ) ) ENDIF
RETURN .F.
METHOD AddProperty( cName, xVal ) CLASS TWndData
LOCAL o := Self
If HB_ISCHAR( cName ) .and. ! __objHasData( o, cName ) If ! Empty( __objAddData( o, cName ) ) RETURN ! Empty( __ObjSetValueList( o, { cName, xVal } ) ) EndIf EndIf
RETURN .F.
METHOD DelProperty( cName ) CLASS TWndData
LOCAL o := Self
If HB_ISCHAR( cName ) .and. __objHasData( o, cName ) RETURN Empty( __objDelData( o, cName ) ) EndIf
RETURN .F.
METHOD GetListType() CLASS TWndData
LOCAL oType := oKeyData() LOCAL aType := {}
::oName:Eval({|k,o,i| k := i, oType:Set(o:cType, o:cType) }) oType:Eval({|k,v,i| k := i, aAdd(aType, v) }) oType:Destroy() oType := Nil
RETURN aType
METHOD GetObj4Type( cType, lEque ) CLASS TWndData
LOCAL aObj := {}
If ! empty(cType) lEque := hb_defaultValue(lEque, .T.) If ::cChr $ cType; lEque := .F. EndIf FOR EACH cType IN hb_ATokens(upper(cType), ::cChr) ::oName:Eval({|ky,oc,ni| ky := ni, iif( lEque, iif( cType == oc:cType, aAdd(aObj, oc), ), ; iif( cType $ oc:cType, aAdd(aObj, oc), ) ) }) NEXT EndIf
RETURN aObj
METHOD GetObj4Name( cName ) CLASS TWndData
LOCAL aObj := {}
If ! empty(cName) FOR EACH cName IN hb_ATokens(cName, ::cChr) ::oName:Eval({|ky,oc,ni| ky := ni, iif( cName $ oc:cName, aAdd(aObj, oc), Nil ) }) NEXT EndIF
RETURN aObj
METHOD DoEvent ( Key, nHandle, nParam, cEvent ) CLASS TWndData
/* * Создание объекта класса TKeyData, если задан параметр Obj, то в блоки кода * метода Do(...) передается значение Obj, иначе Self. * Для использования в потоках, задаем значение параметра lVmMt := hb_mtvm(). */ *-----------------------------------------------------------------------------* FUNCTION oKeyData( Obj, lVmMt ) *-----------------------------------------------------------------------------* RETURN TKeyData():New():Def(Obj, lVmMt)
////////////////////////////////////////////////////////////////////////////////////////////// CLASS TKeyData //////////////////////////////////////////////////////////////////////////////////////////////
PROTECTED: VAR oObj VAR aKey INIT hb_Hash() VAR lMT INIT .F.
SYNC METHOD SGD( n, k, v )
EXPORTED: VAR Cargo
METHOD New() INLINE ( Self ) CONSTRUCTOR
METHOD Def( o, lVmMt ) INLINE ( ::Obj := o, ::MT := lVmMt, Self )
/* * Для работы в потоках, синхронизируется доступ к контейнеру ::aKey */ METHOD SGD( n, k, v ) CLASS TKeyData
SWITCH n CASE 1 hb_HSet( ::aKey, k, v ) EXIT CASE 2 RETURN hb_HGetDef( ::aKey, k, v ) EXIT CASE 3 If hb_hHasKey( ::aKey, k ) hb_HDel ( ::aKey, k ) EndIf EXIT CASE 4 RETURN { hb_HKeyAt( ::aKey, k ), hb_HValueAt( ::aKey, k ) } EXIT END
RETURN Nil
/* * Выполнение блока кода Block над всеми элементами контейнера данных ::aKey. * Кодоблоку передаются ключ, значение и индекс. * Если параметр Block, не блок кода, возвращается массив значений, где * каждый элемент массив { ключ, значение, индекс } * Примеры использования в классе TWndData: * METHOD GetListType() * METHOD GetObj4Type( cType, lEque ) * METHOD GetObj4Name( cName ) */ METHOD Eval( Block ) CLASS TKeyData LOCAL m, i, b := HB_ISBLOCK(Block) LOCAL a := iif( b, Nil, array(0) )
For i := 1 To ::Len If ::lMT m := ::SGD( 4, i ) If b; Eval( Block, m[ 1 ], m[ 2 ], i ) Else; aAdd( a, { m[ 1 ], m[ 2 ], i } ) EndIf Else If b; Eval( Block, hb_HKeyAt( ::aKey, i ), hb_HValueAt( ::aKey, i ), i ) Else; aAdd( a, { hb_HKeyAt( ::aKey, i ), hb_HValueAt( ::aKey, i ), i } ) EndIf EndIf Next
RETURN a
/* * Выполнение операции суммирования над элементом контейнера данных с ключем Key. * xSum может быть числом или массивом, тогда суммируются только числовые элементы. * В качестве ключа можно использовать имена контролов, тогда возникает связка, при * событийном программировании, с событием заполнения Value контрола из контейнера. * Пример: Local o := oKeyData() * Local Als := oBrw1:cAlias * o:Sum("PRIHOD", { 0, 0, 0 }) * o:Sum("RASHOD", { 0, 0, 0 }) * DO WHILE ! Eof() * o:Sum("COUNT" , 1) * o:Sum("KOLVO" , (Als)->KOLVO) * o:Sum("SUMMA" , (Als)->SUMMA) * If (Als)->OPER == "PRI" * o:Sum("PRIHOD", { 1, (Als)->KOL_PRI, (Als)->SUM_PRI }) * ElseIf (Als)->OPER == "RAS" * o:Sum("RASHOD", { 1, (Als)->KOL_RAS, (Als)->SUM_RAS }) * EndIf * SKIP * ENDDO * ? o:Get("COUNT"), o:Get("KOLVO"), o:Get("SUMMA") * ? hb_valtoexp(o:Get("PRIHOD")) * ? hb_valtoexp(o:Get("RASHOD")) */ METHOD Sum( Key, xSum ) CLASS TKeyData
LOCAL sum := ::Get( Key, 0 )
If HB_ISNUMERIC( xSum ) If HB_ISNUMERIC( sum ); sum += xSum Else ; sum := xSum EndIf ::Put( Key, sum ) ElseIf HB_ISARRAY( xSum ) If HB_ISARRAY(sum) .and. Len(sum) == Len(xSum) AEval(xSum, {|s,i| sum[ i ]:= iif( HB_ISNUMERIC( s ), sum[ i ] + s, s ) } ) Else sum := xSum EndIf ::Put( Key, sum ) EndIf
RETURN Nil
/* * Освобождение собственных переменных объекта, устанавливаем в Nil. */ METHOD Destroy() CLASS TKeyData
LOCAL i, k, o
If HB_ISHASH( ::aKey ) For i := 1 To Len( ::aKey ) k := hb_HKeyAt( ::aKey, i ) hb_HSet( ::aKey, k, Nil ) hb_HDel( ::aKey, k ) Next EndIf
If HB_ISOBJECT(::Cargo) .and. ::Cargo:ClassName == ::ClassName o := ::Cargo If HB_ISHASH( o:aKey ) For i := 1 To Len( o:aKey ) k := hb_HKeyAt( o:aKey, i ) hb_HSet( o:aKey, k, Nil ) hb_HDel( o:aKey, k ) Next EndIf EndIf
::oObj := ::aKey := ::Cargo := Nil
RETURN Nil
Пример, который выкладывал ранее, работает и там и там.
Кому интересно. Выкладываю классы для vm и vmmt режимов hb.
Да всем будет интересно. Не сейчас, так позже понадобиться.
gfilatov пишет:
цитата:
Если у Вас есть интересные наработки для включения в новый релиз, то сейчас самое удобное время для их отправки мне
Григорий включи пожалуйста в библиотеку. А то проработанные и хорошие идеи пропадают !
Петр
постоянный участник
Пост N: 1525
Зарегистрирован: 09.10.06
Отправлено: 17.06.17 23:26. Заголовок: Andrey пишет: А то ..
Andrey пишет:
цитата:
А то проработанные и хорошие идеи пропадают !
На счет хорошие или нет - не скажу, не знаю, а вот чтобы проработанные - это еще вопрос.
SergKiss скажите, вот у вас обьекты создаются по такой схеме *-----------------------------------------------------------------------------* FUNCTION oKeyData( Obj, lVmMt ) *-----------------------------------------------------------------------------* RETURN TKeyData():New():Def(Obj, lVmMt)
Т.е. у вас метод Def фактически является конструктором
Скажите почему вы игнорируете подсказку разработчика
"and please remember that :NEW() will be class method so it should not be redefined as constructor in user class. Instead :INIT() method should be used as constructor. It's executed automatically when object is created from the :NEW() method."
Какой смысл вы вкладываете в существование такого кода ACCESS MT INLINE ::lMT ASSIGN MT( lVmMt ) INLINE ::lMT := iif( HB_ISLOGICAL(lVmMt), lVmMt, .F. )
а такого ACCESS Obj INLINE ::oObj ASSIGN Obj( o ) INLINE ::oObj := iif( HB_ISOBJECT(o), o, Self )
такого ACCESS Show INLINE _ShowControl ( ::cName, ::oWin:cName ) METHOD Show() INLINE _ShowControl ( ::cName, ::oWin:cName )
PS. Если ответ будет типа: и так работает; боюсь, что вы не поймете; некогда думать, надо по клаве стучать или "вам шашечки или ехать" - оставьте, пожалуйста, вопросы без внимания.
SergKis
постоянный участник
Пост N: 1548
Зарегистрирован: 17.02.12
Отправлено: 18.06.17 14:36. Заголовок: Петр Спасибо за кон..
Петр Спасибо за конкретные вопросы.
цитата:
такого ACCESS Show INLINE _ShowControl ( ::cName, ::oWin:cName ) METHOD Show() INLINE _ShowControl ( ::cName, ::oWin:cName )
Это аналог (как в псевдо ООП на препроцессоре) исп. o:Show и o:Show()
цитата:
а такого ACCESS Obj INLINE ::oObj ASSIGN Obj( o ) INLINE ::oObj := iif( HB_ISOBJECT(o), o, Self )
1. Я скрыл, что вн. переменная имеет префикс oObj - хранение объектов 2. access\assign предполагает, что в дальнейшем, я должен использовать везде, в том числе и внутри класса только эти определения. Что бы в дальнейшем, подправив\изменив assign мне не требовалось править весь текст класса, а еще хуже программы. Я, кстати, нарушил это правило (что не есть хорошо), но только по причине, что классы небольшие.
цитата:
Какой смысл вы вкладываете в существование такого кода ACCESS MT INLINE ::lMT ASSIGN MT( lVmMt ) INLINE ::lMT := iif( HB_ISLOGICAL(lVmMt), lVmMt, .F. )
Не очень понимаю вопрос. Делал так, по причине, не привязываться к ф-ии hb_mtvm() внутри класса, не знаю как она называется в xhb, но главное, считаю (во многих случаях), что в среде vmmt, вполне можно работать без совместного доступа к классам - это в руках делающего программу. К примеру, если в потоке создаем окно с сопутствующими классами, то не х... лезть в него из др. потоков. Если очень надо, для этого есть сообщения, т.е. послали по handle и пусть идет ... А делать всегда совместный доступ - это удорожание продукта, трата времени и ...
цитата:
вот у вас обьекты создаются по такой схеме *-----------------------------------------------------------------------------* FUNCTION oKeyData( Obj, lVmMt ) *-----------------------------------------------------------------------------* RETURN TKeyData():New():Def(Obj, lVmMt)
Т.е. у вас метод Def фактически является конструктором
Мы в процедурной среде. oKeyData(...) это аналог функций _Difine...(...). Кстати, забыл, а надо бы добавить и можно это сделать не залезая в класс FUNCTION oKeyData( Obj, lVmMt ) *-----------------------------------------------------------------------------* Default lVmMt := hb_mtvm() RETURN TKeyData():New():Def(Obj, lVmMt)
Нет, конструктором является :New(), то что он пустышка - это частный случай Если бы сделал
то исп. в нем ::MT := lVmMt было бы не очень правильно, т.к. конструктор не закончился, а мы суем ему уже разные внутренние конструкции. А написав (фактически продублировав свойство assign) мы в будущем могли попасть на неприятности, модификации дубляжа. Потому применение Def вполне оправдано, а честнее, только так и надо поступать. Утрированный пример. Делаем (не в среде hmg) o := oWndData(....) для окна A, поработали, надо также поработать с окном Б, можем создавать новыу переменную окна, а можем вызвать :Def(...) существующего и по тому же тексту, что работал с А отработать Б.
Еще про access\assign. Имеем ACCESS AAAA INLINE .... ASSIGN AAAA( p ) INLINE .... используем по полной и через время понадобилось немного изменить, но не влазит по потребностям в assign, то подправить ситуевину можно добавив METHOD AAAA( p, p1 ) INLINE ... и старое работает и новое есть. При исп. (хорошая команда) SETGET мы имеем чуть другое
Петр
постоянный участник
Пост N: 1526
Зарегистрирован: 09.10.06
Отправлено: 18.06.17 16:22. Заголовок: SergKis пишет: Это ..
SergKis пишет:
цитата:
Это аналог (как в псевдо ООП на препроцессоре) исп. o:Show и o:Show()
Т.е. ради сомнительного синтаксического сиропа вы просто так добавили еще один метод, который и не нужен честно говоря. SergKis пишет:
цитата:
1. Я скрыл, что вн. переменная имеет префикс oObj - хранение объектов 2. access\assign предполагает, что в дальнейшем, я должен использовать везде, в том числе и внутри класса
От кого вы скрыли, oObj находится в PROTECTED и не может использоваться вне класса. Но я, вообще-то, не о том. Вот как только вы открыли свой код для других можете быть уверенны, что кто-то воспользуется не так как надо. Почему в ASSIGN нет никаких проверок и в чем прикол хранить в переменной обьекта ссылку на сам обьект? SergKis пишет:
цитата:
Не очень понимаю вопрос. Делал так, по причине, не привязываться к ф-ии hb_mtvm() внутри класса, не знаю как она называется в xhb, но главное, считаю (во многих случаях), что в среде vmmt, вполне можно работать без совместного доступа к классам - это в руках делающего программу. К примеру, если в потоке создаем окно с сопутствующими классами, то не х... лезть в него из др. потоков. Если очень надо, для этого есть сообщения, т.е. послали по handle и пусть идет ... А делать всегда совместный доступ - это удорожание продукта, трата времени и ...
Это все ИМХО. Вы, я и др. не можем управлять многопоточностью в своей программе. Вот прилинковали соотв. библиотеку и от этого пляшем. Ну если вам так нужна эта lVmMt (мое мнение - не нужна ) то можно просто добавить, не раздувая класса CLASSVAR lVmMt INIT hb_mtvm() READONLY
SergKis
постоянный участник
Пост N: 1549
Зарегистрирован: 17.02.12
Отправлено: 18.06.17 17:41. Заголовок: Петр пишет Т.е. ради..
Петр пишет
цитата:
Т.е. ради сомнительного синтаксического сиропа вы просто так добавили еще один метод, который и не нужен честно говоря.
Если вы считаете, что привыкнув писать с псевдо ООП .Show или .Show(), дадим только:Show(), нет вопросов убирайте. А "добавили еще один метод, который и не нужен честно говоря" - это из серии "сколько бухгалтеров столько и бухгалтерий".
цитата:
От кого вы скрыли, oObj находится в PROTECTED и не может использоваться вне класса.
Вообще то, есть правила хорошего тона при программировании, сообщать, что хранится в веденной переменной. Введя o я сказал, что там объект и не надо делать операций проверок и не важно в какой области класса эта переменная. Что бы не было как TsColumn :nAlign - вроде для числа, а там и блоки и ...., про TsBrowse вообще молчу.
цитата:
Почему в ASSIGN нет никаких проверок и в чем прикол хранить в переменной обьекта ссылку на сам обьект?
Про какое место разговор. если про TKeyData, то я написал "то в блоки кода метода Do(...) передается значение Obj, иначе Self. " и применил
т.е. в блоки кода будет передан объект окна или контрола, а не только свой Self. Вы можете иметь свой объект, иметь набор блоков для исполнения с каким то др. объектом, вы можете выполнить те же блоки со своим, сделав o:Obj := <ваш объект>
цитата:
CLASSVAR lVmMt INIT hb_mtvm() READONLY
Я сказал ранее, повторю, не хочу связывать объект с функцией hb_mtvm(), т.к. это связывает руки при использовании класса. Я, к примеру, в потоках не буду использовать совместно данные объектов, т.е. даже в vmmt у меня будет всегда .F. Я предлагал _HMG_MainCargo := oKeyData() _HMG_MainCargo:Set('bFormInit', Nil) _HMG_MainCargo:Set('bFormDestroy', Nil) _HMG_MainCargo:Set('bControlInit', Nil) _HMG_MainCargo:Set('bControlDestroy', Nil) можно подправить и добавить _HMG_MainCargo := oKeyData( , hb_mtvm()) _HMG_MainCargo:Set('lModeVmMt', .F.) или hb_mtvm() и в функциях oWndData, oKeyData заменить Default lVmMt := _HMG_MainCargo:Get('lModeVmMt') ...
Если вы считаете, что привыкнув писать с псевдо ООП .Show или .Show(), дадим только:Show(), нет вопросов убирайте.
Кто вам сказал, что все убегут с псевдо на ООП? Вы используйте рационально ресурсы компьютера и все, всех остальных компилятор быстро научит "родину любить". SergKis пишет:
цитата:
Вообще то, есть правила хорошего тона при программировании, сообщать, что хранится в веденной переменной. Введя o я сказал, что там объект и не надо делать операций проверок и не важно в какой области класса эта переменная. Что бы не было как TsColumn :nAlign - вроде для числа, а там и блоки и ...., про TsBrowse вообще молчу.
Венгерская нотация еще никому ничего не гарантировала, тем более в нетипизированных языках. В METHOD Destroy() CLASS TKeyData тогда зачем проверок напихали? Может опять какой то префикс замутить и хватит. Типа VAR aKey INIT hb_Hash()
Так, что за необходимость хранить в переменной обьекта ссылку на сам обьект?
цитата:
ASSIGN Obj( o ) INLINE ::oObj := iif( HB_ISOBJECT(o), o, Self )
SergKis пишет:
цитата:
если про TKeyData, то я написал "то в блоки кода метода Do(...) передается значение Obj, иначе Self. " и применил METHOD Def
Ну написали, я прочитал и что? Почему так "кучеряво" написали?
цитата:
Я сказал ранее, повторю, не хочу связывать объект с функцией hb_mtvm(), т.к. это связывает руки при использовании класса. Я, к примеру, в потоках не буду использовать совместно данные объектов, т.е. даже в vmmt у меня будет всегда .F.
Какие руки (oHand?), каким образом? Эта функция линкуется в любой harbour бинарник при использовании ключа -mt. Прямой ее вызов в нужном месте "дешевле" хранения стандартных переменных и тем более переменных обьекта, не говоря про методы ACCESS MT INLINE ::lMT ASSIGN MT( lVmMt ) INLINE ::lMT := iif( HB_ISLOGICAL(lVmMt), lVmMt, .F. )
Вот вы не собираетесь использовать, я тоже, если Андрею придется использовать TKeyData в mt режиме и у него будет .T., может он рассчитывать на безопасность этого класса? И если да, то чем вы ее обеспечили?
SergKis
постоянный участник
Пост N: 1550
Зарегистрирован: 17.02.12
Отправлено: 19.06.17 15:25. Заголовок: Петр пишет Венгерс..
Петр пишет
цитата:
Венгерская нотация еще никому ничего не гарантировала, тем более в нетипизированных языках Так, что за необходимость хранить в переменной обьекта ссылку на сам обьект? Ну написали, я прочитал и что? Почему так "кучеряво" написали?
ASSIGN Obj( o ) INLINE ::oObj := iif( HB_ISOBJECT(o), o, Self ) как раз и гарантирует "венгерскую нотацию", обеспечивая в переменной объект. o := oKeyData({||...}) или o:Obj := {||...} кроме объекта иное не пройдет. потому везде смело работайте с o:Obj как с объектом, без проверок типов.
Объсню "кучерявость". Смысл :Obj в том, что он передается в блок кода, который зарегистририван в :aKey (их, блоков, может быть много). Если менять в :Obj ссылку с Self на ссылку др. объекта, то блоки, при выполнении, будут получать уже этот объект по ссылке. Т.е. когда создается объект TWndData\TCnlData, работает метод :Def(...), создаются объекты контейнеры CLASSDATA oName INIT oKeyData() CLASSDATA oHand INIT oKeyData() ::oCargo := oKeyData() ::oUserKeys := oKeyData() для этих в :Obj будет собственный адрес объекта Self ::oEvent := oKeyData( Self ) этот занесет в :Obj значения адреса объекта, в зависимости от того, какой объект создается TWndData или TCnlData. Таким образом решается вопрос передачи в события нужного объекта, т.е. блоки коды событий, зарегистрированные на окно, получат объект своего окна. К примеру события окна win_1 получат, в блоке кода, ссылку на объект win_1, для win_2 и т.д. будет тоже самое, т.е. доступны o:Index, o:Handle, o:Name, ... окна. Точно так же работают зарегестрированные события (блоки кода) и на контролах, т.е в блоке кода будет объект собственного контрола, т.е. доступны o:Index, o:Handle, o:Name, ... контрола. Это основное предназначение :Obj. Но можно делать и так: Пример. Имеем oBrw1 на окне 1, он решает задачи (в блоках кода), зарегистированные в o := oKeyData(oBrw1) o:Set("Ras4et1", {|ob,ky| ... }) o:Set("Ras4et2", {|ob,ky| ... }) o:Set("Ras4et3", {|ob,ky| ... }) ... На каких то событиях, а может просто где то, используем: в oBrw1 ставим нужные пользователю scope, filter ... и считаем o:Do("Ras4et1", {|ob,ky| ... }) o:Do("Ras4et2", {|ob,ky| ... }) o:Do("Ras4et3", {|ob,ky| ... }) результаты куда то отправляем На др. окнах тот же тсб будет иметь имя oBrw2 или другое, сделав o:Obj := oBrw2 можно выполнять теже блоки, они получат ссылку на объект oBrw2. ... С любым обектом можете проделать такое же. Даже объект TaskDialog можно передать.
цитата:
В METHOD Destroy() CLASS TKeyData тогда зачем проверок напихали?
Если использовали :Cargo как oKeyData(), я проделываю все как с :aKey. Для hb хватило бы и o := Nil или уничтожение локальной переменной, приводило бы к автоматическому вызову :Destroy(). Но в xhb, от вас узнал, этого нет, поэтому, как вы говорите, "понапихал" принудительные вызовы Destroy(), значит возможны "лишние" вызовы, это просто учтено в Destroy().
METHOD GetListType() CLASS TWndData
LOCAL oType := oKeyData() LOCAL aType := {}
::oName:Eval({|k,o,i| k := i, oType:Set(o:cType, o:cType) }) oType:Eval({|k,v,i| k := i, aAdd(aType, v) }) oType:Destroy() oType := Nil
RETURN aType
выделенное для hb можно не делать
цитата:
Эта функция линкуется в любой harbour бинарник при использовании ключа -mt Прямой ее вызов в нужном месте "дешевле" хранения стандартных переменных и тем более переменных обьекта
Причем здесь линкование hb_mtvm() ? Если я, сделаю, как вы предлагали, зашить в класс hb_mtvm CLASSVAR lVmMt INIT hb_mtvm() READONLY Возможно, что вы что то удешивили, но получили только 2-а состояния .T. и .F. А, я, хотел получить ИМЕННО внешнее управление, что бы при hb_mtvm() .T., поставить в объект окна\контрола - .F. Причем здесь "дешевле", если это удобно, минимум ЧЕЛОВЕЧЕСКИХ затрат и решаются просто, это так же относится и .Show, .Show(), :Show, :Show(), ... . Что вы пытаетесь экономить ? Все классы hb просто небольшие, в сравнении с классами VO со строгим стилем программирования. Программы VO как и clipper шустро работали на очень слабеньких машинах.
цитата:
Вот вы не собираетесь использовать, я тоже, если Андрею придется использовать TKeyData в mt режиме и у него будет .T., может он рассчитывать на безопасность этого класса? И если да, то чем вы ее обеспечили?
Я был бы рад, сказать, Я ОБЕСПЕЧИЛ ...), но к радости это обеспечивает hb, вернее SYNC METHOD ... . hb обеспечивает синхронизацию выполнения мтодов в потоках (на мутексах). Потому с классом TKeyData должно быть все хорошо в mt, синхронизированный метод доступа к контейнеру :aKey организован. Следовательно и TWndData, TCnlData что касается работы с контейнерами - будет нормально, а что касается вызовов функций в hmg методах класса - это как было. Работу hmg классами я не затрагивал. Как было, так осталось. Делал Андрей в WaitWindow_2 в потоке окно ... это я ничего не трогал и безопасность не обеспечивал.
Если я, сделаю, как вы предлагали, зашить в класс hb_mtvm CLASSVAR lVmMt INIT hb_mtvm() READONLY Возможно, что вы что то удешивили, но получили только 2-а состояния .T. и .F. А, я, хотел получить ИМЕННО внешнее управление
Петр пишет:
цитата:
Ну если вам так нужна эта lVmMt (мое мнение - не нужна ) то можно просто добавить, не раздувая класса
А можно добавить в EXPORTED секцию VAR lVmMt INIT что-то там и иметь внешнее управление, в большинстве случаев в Clipper так и работали.
цитата:
Причем здесь "дешевле", если это удобно, минимум ЧЕЛОВЕЧЕСКИХ затрат и решаются просто, это так же относится и .Show, .Show(), :Show, :Show(), ... .
:Show и :Show() - разницу в затратах ЧЕЛОВЕЧЕСКИХ определите? Есть ведь еще сопровождение и там затраты ничуть не меньше. Каждый раз в исходники лезть не очень то и комфортно.
цитата:
METHOD GetListType() CLASS TWndData
LOCAL oType := oKeyData() LOCAL aType := {}
::oName:Eval({|k,o,i| k := i, oType:Set(o:cType, o:cType) }) oType:Eval({|k,v,i| k := i, aAdd(aType, v) }) oType:Destroy() oType := Nil
RETURN aType
выделенное для hb можно не делать
В GetListType oType нафиг не нужен, он там за уши притянут, как и большинство ваших ASSIGN/ACCESS.
SergKis
постоянный участник
Пост N: 1551
Зарегистрирован: 17.02.12
Отправлено: 20.06.17 11:41. Заголовок: Петр пишет нафиг не ..
Петр пишет
цитата:
нафиг не нужен, он там за уши притянут, как и большинство ваших ASSIGN/ACCESS
Давайте определимся, класс TaskDialog не типизированный, т.е. работаем как в Clipper и др. не типизированных языках, т.е. убрав все методы SETGET в классе ничего не изменится, как был не типизированным, так и остался. Представленные классы написаны в строго типизированном стиле, где доступы к переменным осуществляются через ACCESS\ASSIGN (методы и там и там) и объявления переменных должны быть типизированы. Последнее пока не сделал (только для объектов AS OBJECT сделал) из за метода Destroy(). Если пропишу AS STRING, AS NUMERIC, AS LOGIC, то в Destroy() должен присваивать не NIL, а соответсвующие объявлению значения, в hb я не знаю хорошо ли в Destroy() сделать ::cName := "", ::nHandle := 0, ... подвиснут или уберутся. Потому предложение убрать ACCESS\ASSIGN или заменить на SETGET переведет класс в не типизированный. Если бы я этого хотел, так писал сразу. Да, набирать классы начинал не типизированными, но постепенно переводил в строгую типизацию.
цитата:
А можно добавить в EXPORTED секцию VAR lVmMt INIT что-то там и иметь внешнее управление, в большинстве случаев в Clipper так и работали.
Даже, если вы так сделаете, все равно придется добавлять метод для установления свойства :MT в объектах TKeyData (тут ASSIGN, у вас может SETGET или просто метод)
:Show и :Show() - разницу в затратах ЧЕЛОВЕЧЕСКИХ определите? Есть ведь еще сопровождение и там затраты ничуть не меньше. Каждый раз в исходники лезть не очень то и комфортно.
В данном случае, вы определили только программистские затраты и не учли затраты эксплуатационные. Т.е. не дали :Show. Пользователь hmg, неважно каким способом, написал где то в одном месте так. Проверял ..., (что бы все режимы проверить, возможно, надо держать человека или группу), но отвлекли, ..., пропустил. Ушло в эксплуатацию, режим с ошибкой редкий, раз в месяц. И как, бутерброд с маслом, вылезет в неподходящее время. И что дороже, продублировать несколько строк, в каждой исправив несколько букв или заложить мину ? Я говорю о данном случае, а не вообще ... .
цитата:
В GetListType oType нафиг не нужен
Предложите реализацию получения уникального списка типов по другому. Я сделал так.
Andrey
постоянный участник
Пост N: 5423
Зарегистрирован: 12.09.06
Отправлено: 20.06.17 12:45. Заголовок: Петр да помоги напис..
Петр да помоги написать как нужно и всех делов то... Меньше ругани - больше дела !
Петр
постоянный участник
Пост N: 1530
Зарегистрирован: 09.10.06
Отправлено: 20.06.17 13:26. Заголовок: Andrey пишет: Петр ..
Andrey пишет:
цитата:
Петр да помоги написать как нужно и всех делов то...
Кому от этого легче станет? Пускай человек учится..
Петр
постоянный участник
Пост N: 1531
Зарегистрирован: 09.10.06
Отправлено: 20.06.17 13:36. Заголовок: Петр пишет: через A..
Петр пишет:
цитата:
через ACCESS\ASSIGN (методы и там и там) и объявления переменных должны быть типизированы. Последнее пока не сделал (только для объектов AS OBJECT сделал) из за метода Destroy(). Если пропишу AS STRING, AS NUMERIC, AS LOGIC, то в Destroy() должен присваивать не NIL, а соответсвующие объявлению значения, в hb я не знаю хорошо ли в Destroy() сделать ::cName := "", ::nHandle := 0, ... подвиснут или уберутся. Потому предложение убрать ACCESS\ASSIGN или заменить на SETGET переведет класс в не типизированный. Если бы я этого хотел, так писал сразу. Да, набирать классы начинал не типизированными, но постепенно переводил в строгую типизацию.
Значит класс не закончен и смотреть не на что. И не пишите, пожалуйста, то чего не знаете - я не знаю как на это реагировать, ну типа плакать или смеяться Я привел вам пример (destruct.prg) - там и деструктор и неявный конструктор init.. Там (папка tests) есть и другие примеры, например, реализация FOREACH, OPERATOR для классов - очень даже интересно.
Все даты в формате GMT
3 час. Хитов сегодня: 219
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет