Форум » [x]Harbour » hbini.prg » Ответить

hbini.prg

krutoff: Покрутил, потестировал функцию hb_iniRead для работы с ini-файлами. Хочу поделиться мыслями: В память закачивается дерево хэш массивов. Комментарии ';' и '#' игнорируются. Вообще все строки, где нет разделителя "=" - идут в игнор. И если затем записать файл с помощью hb_iniWrite - то в файле будут только секции со строками key = valiue

Ответов - 15

SergKis: krutoff пишет Покрутил, потестировал функцию hb_iniRead для работы с ini-файлами посмотрите в MiniGui h_objects.prg (исп. этой ф-ии) ... CLASS TIniData INHERIT THmgData ... и примеры со строками[pre2] oIni := TIniData():New(cIni, .T.):Read() ... //oIni := TIniData():New(cIni, .T.):Read() - значения для ключей будут форматированы по типам //oIni := TIniData():New(cIni, .F.):Read() - значения для ключей будут только типа "C" //oIni := oIniData( cFileDcrp, .T., lUtf8, ):Read() - это читать из файла //oIni -> это hash с вложенными hash секциями и вложенными в них hash ключами // считать настройку cnfg-файл в переменную oCnf из переменной cBuff oCnf := TIniData():New( , .T., lUtf8, , cBuff ):Read() ... и т.д. [/pre2]

krutoff: Спасибо за ответ, Сергей! Воспользовался Вашим советом. Получилось вот что. Сразу скажу, что мне бывает необходимо закинуть просто текст в секцию с маркерами для подстановки значений. Раньше это делал с помощью _getPrivateProfileSection(). Тут такого нет. Кстати hb_iniRead обрабатывает фразу include и вставляет секции из include-файла. Ну вот. Есть файл Test1.ini: ;include OI.ini # Commen1 [HELP] Ctrl+F Поиск по полю F3: Продолжение поиска [D_OI] 1=1. Проміжна інформація #Comment2 ;Comment3 2=2. Особлива інформація 3=3. Інша інформація Выполняю 2 строки oIni := TIniData():New('Test1.ini', .F.):Read() oIni:Write('Test2.ini') Результат Test2.ini: # Commen1 [HELP] [D_OI] 1 = 1. Проміжна інформація 2 = 2. Особлива інформація 3 = 3. Інша інформація

SergKis: krutoff пишет мне бывает необходимо закинуть просто текст в секцию с маркерами для подстановки значений. С TIniData не важно, есть ini или нет (ключи в секциях есть или нет), вы всегда можете работать с переменными oIni объекта (по мне, доступ к переменным в объекте-контейнере oIni удобнее, чем в hash). В примере Advanced\App_OopTemplate есть файлы ini, cfg, Андрей написал даже info комментарии в них и в prg, смотрите. Хранить в TIniData можно данные по типам C,N,L,D,A,B и даже данные объекта THmgData (ф-я o := oHmgData(), ...) как json данные, т.е. это несколько больше, чем просто файл ini. Создается, проверяется все оч. просто, примерно так[pre2] App.Cargo := oHmgData() ; o := App.Cargo ... o:lIni := hb_FileExists(cIni) // доступ к ини-файлу везде в программе - App.Cargo:oIni o:oIni := TIniData():New(cIni, .T.):Read() Default o:oIni:INFO := oHmgData() // <- secija, если ее нет в переменной (ini), будет создана, как и переменные ниже Default o:oIni:INFO:Developed_in := MiniGUIVersion() Default o:oIni:INFO:xBase_compiler := Version() Default o:oIni:INFO:C_compiler := Hb_Compiler() Default o:oIni:INFO:Programm := o:cTitle Default o:oIni:INFO:ProgVers := o:cVersion Default o:oIni:INFO:Avtor := o:cAvtor Default o:oIni:INFO:Email := o:cEmail Default o:oIni:MAIN := oHmgData() // <- secija Default o:oIni:MAIN:ExeFile := App.Exename Default o:oIni:MAIN:aBClrMain := {215, 166, 0} Default o:oIni:MAIN:ComSanMS := { o:cFontName2 , o:nFontSize+2 , .F., .F. } // фонт главного верхнего меню Default o:oIni:MAIN:aWindow := {0, 0, 0, 0} // TsBrowse Default o:oIni:TsBrowse := oHmgData() // <- secija Default o:oIni:TsBrowse:Normal := { o:cFontName, o:nFontSize , .F., .F. } Default o:oIni:TsBrowse:Bold := { o:cFontName, o:nFontSize , .T., .F. } Default o:oIni:TsBrowse:Italic := { o:cFontName, o:nFontSize-2, .F., .T. } Default o:oIni:TsBrowse:ItalBold := { o:cFontName, o:nFontSize-2, .T., .T. } Default o:oIni:TsBrowse:SpecHdr := { o:cFontName, o:nFontSize-2, .T., .T. } Default o:oIni:TsBrowse:SuperHdr := { o:cFontName, o:nFontSize-2, .T., .F. } Default o:oIni:TsBrowse:Edit := { o:cFontName, o:nFontSize+2, .F., .F. } //_o2log(o:oIni, 27, ProcNL() + " o:oIni => ", .T. ) ; ? Default o:oIni:WinDebug := oHmgData() Default o:oIni:WinDebug:Rem := "Координаты окна отладки" Default o:oIni:WinDebug:nY := 0 Default o:oIni:WinDebug:nX := 0 IF !o:lIni // если нет файла, то создадим его o:oIni:cCommentBegin := " Modify: " + hb_TtoC( hb_DateTime() ) o:oIni:Write() // НЕ UTF8, т.е. нет BOM на выходе ENDIF ... [/pre2] Кстати hb_iniRead обрабатывает фразу include и вставляет секции из include-файла. Этим не пользовался, т.к. в объекте-контейнере есть свои варианты слияния нескольких переменных oIni в один, добавление в него hash, array, json данных -> в основе лежит класс THmgData, смотрите его методы и свойства PS. тут https://clipper.borda.ru/?1-4-0-00001425-000-0-0-1729596515 пример использования oHmgData() для разных вычислений (по адресу счетчик) в примере App_OopReport подсчет итогов, т.е. секция это вариант oHmgData() контейнера со всеми вытекающими


krutoff: Сергей, спасибо за ответ! Ваш TiniData очень хорош, мне все тут подходит, если бы не одно но: (правда, это не критично, можно попробовать обойтись и без комментов) Метод TIniData():New(cIni, .T.):Read() использует функцию hb_iniReadStr(), которая глотает комментарии ';' и '#' и на выходе выдает дерево HASH-массивов. Вообще все строки, где нет разделителя "=" - идут в игнор. В Вашем примере Advanced\App_OopTemplate в файле Demo_timer.ini в самом начале файла я поставил: ;COMMENT1 ;COMMENT2 #COMMENT 3 [HELP] Тут должна быть информация #HELP [TEST] 01 = TEST #COMMENT 4 #COMMENT 5 Запустил Demo_timer.exe и сразу закрыл. Начало файла Demo_timer.ini стало таким: #COMMENT 3 [HELP] [TEST] 01 = TEST P.S. Пример использования oHmgData() с hb_memoread(cFileini) очень заинтересовал - применить его вместо hb_iniReadStr, а парсинг hb_iniStringLow() доработать.

SergKis: krutoff пишет Метод TIniData():New(cIni, .T.):Read() использует функцию hb_iniReadStr(), которая глотает комментарии ';' и '#' Как говорится "Не виноватая я, он сам ... ", так работает эта ф-я в hb + она воспринимает "[" в любом месте, как начало новой секции, т.к. в работе часто после = надо ссылаться на секцию, для настройки, то в примерах и для json вместо "[","]" используются скобки "<",">", для ";" есть переменная объекта VAR cCommentChar AS STRING INIT ";", которую можно сменить параметром TIniData():New( cIni, lMacro, lUtf8, cChar, cData, cSrcChar, cOutChar ) выделенное синим, позволяет на лету делать подмену символа при чтении строки (METHOD ToValue( cStr )), т.е.[pre2] IF !Empty( ::cSrcReplChar ) cStr := StrTran( cStr, ::cSrcReplChar, ::cOutReplChar ) ENDIF[/pre2] Запустил Demo_timer.exe и сразу закрыл. Начало файла Demo_timer.ini стало таким: Особенность работы с TIniData еще в том, что (по мне) ini, cfg файлы надо набирать руками, как настроечные, тогда коменты в строках "; ..." с "=" будут сохранены (с "#" остается как было, так работают ф-ии). Если создать ini, cfg программно и потом внести коменты, то эти файлы можно класть в ресурсы, как базовые настройки, менять некоторые настройки в них (привязка к клиенту) можно из обычных файлов ini, cfg у конкретного клиента, сделав чтение и слияние с данными oIni из ресурсов. Еще всегда есть возможность обработки файла своими средствами, прочитав в буффер cBuff := hb_memoRead(cFile), обработать как вам надо, ... и потом формировать секции и ключи для работы в переменной oCnf := TIniData():New( , .T., lUtf8, , cBuff ):Read() Для программного формирования файлов с комментами, надо для символов комментариев использовать другие данные, отличные от тех, которые исп. родные ф-ии hb при чтении файлов, если это надо PS. запись в ini [HELP] Тут должна быть информация #HELP всегда можно заменить на [HELP] Rem = Тут должна быть информация ;HELP или [HELP] Help1 = Тут должна быть информация Help2 = ... ... или [HELP] Help = {"Тут должна быть информация", "#HELP", ...} ; тут текст коммента

krutoff: Сергей, спасибо за детальное пояснение! Стратегия работы с ini-файлами у меня практически такая же. Попробую все перевести на TiniData. Тут возможностей больше. Спасибо!

krutoff: А нельзя в методе Read( cIniNew ) CLASS TIniData переопределить символ '#' У меня в ini есть куча строк типа #WIDTH =550;550 К примеру #WIDTH использую как ключевое слово, а не параметр.

SergKis: krutoff Для информации, вариант исп. в oHmgData() контейнере псевдо методов (блоки кода) и выполнение их методом :Do(...) Это кусочек кода из примера "Testing DEMO Odbc/Firebird" (в hmg его нет)[pre2]*----------------------------------------------------------------------------* FUNCTION oFDB_Connect(cFdb, cUsr, cPsw, cErr, lNoDbf) *----------------------------------------------------------------------------* LOCAL oac := App.Cargo LOCAL o := oHmgData(), cPref, cMsg, cKod, nCnt LOCAL cSql, aRec, cTbl, aFld, cFld, nFld, aStru, oField STATIC s_oFdb ; IF s_oFdb == NIL ; s_oFDB := oHmgData() ; ENDIF // регистация баз в работе IF Empty(s_oFdb:Get(cFdb)) ; s_oFdb:Set(cFdb, hb_FNameName(cFdb)) ENDIF cPref := "_" + cValToChar(s_oFdb:Pos(hb_FNameName(cFdb))) Default cUsr := "SYSDBA", cPsw := "masterkey", lNoDbf := .F. Default cErr := "ERROR!;Can't connect to database !" o:cDriver := 'DRIVER=Firebird/InterBase(r) driver;UID=^1;PWD=^2;DBNAME=^3;' o:cConnect := o:cDriver o:aTables := {} o:oTables := oHmgData() o:oFields := oHmgData() o:cConnect := StrTran(o:cConnect, "^1", cUsr) o:cConnect := StrTran(o:cConnect, "^2", cPsw) o:cConnect := StrTran(o:cConnect, "^3", cFdb) o:cBase := cFdb o:cPref := cPref o:lNoDbf := lNoDbf o:cError := cErr + " " + o:cBase + " " o:cDbfTabl := oac:cPath + "_Tables" o:cDbfStru := oac:cPath + "_TablesStru" o:cAlsTabl := upper(cPref) + "_TABL" o:cAlsStru := upper(cPref) + "_STRU" o:aDbfTabl := {{"R_CODE" , "C", 4, 0 }, ; {"R_TABLE" , "C", 20, 0 }, ; {"R_COUNT" , "N", 7, 0 }} o:aDbfStru := {{"R_CODE" , "C", 4, 0 }, ; {"R_NAME" , "C", 10, 0 }, ; {"F_NAME" , "C", 20, 0 }, ; {"R_TYPE" , "C", 1, 0 }, ; {"R_LEN" , "N", 7, 0 }, ; {"R_DEC" , "N", 5, 0 }, ; {"F_AllowNul", "L", 1, 0 }, ; {"F_DataSize", "N", 10, 0 }, ; {"F_DataType", "N", 3, 0 }} ; // --------------------------------------------- блоки кода - псевдо методы o:ErrorAlert := {|aVal| // ODBC error message Local cMsg, cTxt Local oo := ATail(aVal) // Self cMsg := cTxt := "" IF oo:lError IF Len(aVal) == 2 ; cTxt := aVal[1] ENDIF IF !HB_ISCHAR(cTxt) ; cTxt := cValToChar(cTxt) ENDIF cMsg := oo:cError IF oo:lErrorSql cMsg += CRLF + oo:oConnect:SQLErrorMessage() cMsg += CRLF + oo:oConnect:cSQL ENDIF AlertStop( cTxt + cMsg ) ENDIF Return cMsg } o:Disconnect := {|aVal| // disconnect odbc Local oo := ATail(aVal) // Self IF oo:lConnect oo:oConnect:Destroy() oo:lConnect := .F. oo:lError := .F. oo:lErrorSql := .F. oo:cBase := "" oo:cPref := "" oo:cDbfTabl := "" oo:cDbfStru := "" oo:cAlsTabl := "" oo:cAlsStru := "" ENDIF Return .T. } o:GetTable := {|aVal| // get table R_CODE, R_TABL Local oo := ATail(aVal) // Self Local xTabl := aVal[1] // номер\имя таблицы Local oRet := oHmgData() Local nOldA, cAls Local cTabl, nTabl, lTabl, nKod, nTbl oRet:R_CODE := "" oRet:R_TABLE := "" oRet:N_TABLE := 0 oRet:N_COUNT := 0 IF !oo:lConnect ; Return oRet ENDIF cAls := oo:cAlsTabl + "_TMP" nOldA := Select() USE ( oo:cDbfTabl ) ALIAS ( cAls ) NEW SHARED GO TOP nKod := FieldPos("R_CODE" ) nTbl := FieldPos("R_TABLE") IF IsNumeric(xTabl) ; nTabl := xTabl ELSEIF IsChar(xTabl) ; xTabl := upper(alltrim(xTabl)) ENDIF DO WHILE !EOF() lTabl := .F. IF IsNumeric(xTabl) lTabl := Val(FieldGet(nKod)) == nTabl ELSEIF IsChar(xTabl) cTabl := alltrim(FieldGet(nTbl)) lTabl := upper(cTabl) == xTabl ENDIF IF lTabl oRet:R_CODE := FieldGet(nKod) oRet:R_TABLE := upper(alltrim(FieldGet(nTbl))) oRet:N_COUNT := FieldGet(FieldPos("R_COUNT")) oRet:N_TABLE := RecNo() EXIT ENDIF SKIP ENDDO USE dbSelectArea(nOldA) Return oRet } o:GetTableStru := {|aVal| // get table structure Local oo := ATail(aVal) // Self Local xTabl := aVal[1] // номер\имя таблицы Local nOldA, cAls, nPos Local cFld, cTyp, nLen, nDec, cNam Local oTbl := oo:Do("GetTable", xTabl) oTbl:A_STRU := {} oTbl:O_FIELD := oHmgData() IF Empty(oTbl:N_TABLE) ; Return oTbl ENDIF nPos := 0 cAls := oo:cAlsStru + "_TMP" nOldA := Select() USE ( oo:cDbfStru ) ALIAS ( cAls ) NEW SHARED SET ORDER TO 1 SET SCOPE TO oTbl:R_CODE, oTbl:R_CODE GO TOP DO WHILE !EOF() nPos++ cFld := alltrim((cAls)->&("R_NAME")) cTyp := (cAls)->&("R_TYPE") nLen := (cAls)->&("R_LEN" ) nDec := (cAls)->&("R_DEC" ) cNam := alltrim((cAls)->&("F_NAME")) IF Empty(cFld) ; cFld := "R_" + hb_ntos(nPos) ENDIF IF cTyp == "U" ; cTyp := "C" ENDIF IF nLen == 0 ; nLen := 10 ENDIF AAdd(oTbl:A_STRU, {cFld, cTyp, nLen, nDec, cNam}) oTbl:O_FIELD:Set(cNam, cFld) SKIP ENDDO USE dbSelectArea(nOldA) Return oTbl } o:TablesCount := {|aVal| // count(*) in all tables Local oo := aVal[1] // Self Local nRow := 0, cTbl, lErr FOR EACH cTbl IN oo:aTables nRow := oo:Do('GetRowCount', cTbl) oo:oTables:Set(cTbl, nRow) lErr := nRow < 0 IF lErr ; EXIT ENDIF NEXT Return lErr } o:GetRowCount := {|aVal| // count(*) in table Local nCnt := -1, oo := aVal[2] // Self Local cTbl := aVal[1] Local cSql := "SELECT COUNT(*) FROM " IF oo:lConnect .and. ! oo:lError oo:lError := .F. oo:lErrorSql := .F. oo:oConnect:SetSql( cSql + cTbl ) IF oo:oConnect:Open() nCnt := 0 IF HB_ISARRAY(oo:oConnect:aRecordset) .and. ; Len(oo:oConnect:aRecordset) > 0 nCnt := oo:oConnect:aRecordset[1][1] ENDIF ELSE oo:lError := .T. oo:lErrorSql := .T. ENDIF oo:oConnect:Close() IF oo:lError ; oo:Do('ErrorAlert') ENDIF ENDIF Return nCnt } o:RowSelect := {|aVal| Local oo := ATail(aVal) // Self Local cSql := aVal[1] // 'SELECT ...' Local cTmp := upper(cSql) Local oRet := oHmgData() Local aRec, oFld, nTmp, cTbl IF ( nTmp := At(" FROM ", cTmp) ) > 0 cTmp := ltrim(subs(cTmp, nTmp + 6)) cTbl := left(cTmp, At(" ", cTmp) - 1) ELSE cTbl := cSql cSql := "SELECT * FROM " + cSql ENDIF oRet:cTbl := cTbl oRet:cSql := cSql oRet:lErr := !oo:lConnect oRet:aArr := {} oRet:aFld := {} IF oo:lConnect .and. !oo:lError oo:lError := .F. oo:lErrorSql := .F. oo:oConnect:SetSql( cSql ) IF oo:oConnect:Open() FOR EACH oFld IN oo:oConnect:Fields AAdd( oRet:aFld, oFld:FieldName ) NEXT FOR EACH aRec IN oo:oConnect:aRecordset AAdd( oRet:aArr, AClone(aRec) ) NEXT ELSE oo:lError := .T. oo:lErrorSql := .T. ENDIF oo:oConnect:Close() IF oo:lError oRet:lErr := .T. oRet:aFld := {} oRet:aArr := {} oo:Do('ErrorAlert') ENDIF ENDIF Return oRet } o:GetSqlType := {|aVal| // sql type -> dbf type Local nDataType := aVal[1] Local cType := "U" SWITCH nDataType CASE 1 // SQL_CHAR CASE -8 // SQL_WCHAR CASE -9 // SQL_WVARCHAR CASE 12 // SQL_VARCHAR cType := 'C' EXIT CASE 2 // SQL_NUMERIC CASE 3 // SQL_DECIMAL CASE 4 // SQL_INTEGER CASE 5 // SQL_SMALLINT CASE 6 // SQL_FLOAT CASE 7 // SQL_REAL CASE 8 // SQL_DOUBLE CASE -5 // SQL_BIGINT CASE -6 // SQL_TINYINT cType := 'N' EXIT CASE 9 // SQL_DATE CASE 91 // SQL_TYPE_DATE cType := 'D' EXIT CASE 11 // SQL_TIMESTAMP CASE 93 // SQL_TYPE_TIMESTAMP cType := 'T' EXIT CASE -4 // SQL_BLOB cType := 'B' EXIT ENDSWITCH Return cType } // -------------------------------------------------- o:oConnect := TODBC():New( o:cConnect ) o:lConnect := !Empty( o:oConnect:cODBCRes ) o:lError := !o:lConnect o:lErrorSql := .F. IF o:lError // ERROR ? o:cDriver ; ? "DLL =", hb_FileExists(".\fbclient.dll"), "fbclient.dll" ? o:cConnect ; ? "FDB =", hb_FileExists(o:cBase), o:cBase ? Repl('=', Len(o:cConnect)) AlertStop( o:cError,,,64 ) RETURN o ENDIF // Tables list cSql := 'SELECT rdb$relation_name FROM rdb$relations ' + ; 'WHERE rdb$view_blr IS null AND ' + ; '(rdb$system_flag IS null OR rdb$system_flag = 0) ORDER BY 1' o:oConnect:SetSql( cSql ) IF o:oConnect:Open() FOR EACH aRec IN o:oConnect:aRecordset AAdd( o:aTables, alltrim( aRec[1] ) ) NEXT ELSE o:lError := .T. o:lErrorSql := .T. ENDIF o:oConnect:Close() IF o:lError // ERROR cMsg := o:cError IF o:lErrorSql cMsg += CRLF + o:oConnect:SQLErrorMessage() cMsg += CRLF + o:oConnect:cSQL ENDIF AlertStop( cMsg,,,64 ) RETURN o ENDIF // Tables structure cSql := 'SELECT FIRST 1 * FROM ' FOR EACH cTbl IN o:aTables o:oConnect:SetSql( cSql + cTbl ) IF o:oConnect:Open() aStru := {} FOR EACH oField IN o:oConnect:Fields aFld := array(7) aFld[1] := oField:FieldName aFld[2] := o:Do('GetSqlType', oField:DataType) aFld[3] := oField:DataSize aFld[4] := oField:DataDecs aFld[5] := oField:AllowNull aFld[6] := oField:DataSize aFld[7] := oField:DataType IF aFld[2] == "N" .and. aFld[3] > 18 aFld[3] := 18 ELSEIF aFld[2] == "B" // BLOB or M aFld[3] := 10 ELSEIF aFld[2] == "U" .and. aFld[3] > 999 // ??? aFld[3] := 10 ENDIF AAdd( aStru, aFld ) NEXT o:oFields:Set(cTbl, aStru) ELSE o:lError := .T. o:lErrorSql := .T. ENDIF o:oConnect:Close() IF o:lError ; EXIT // ERROR ENDIF NEXT IF o:lError // ERROR cMsg := o:cError IF o:lErrorSql cMsg += CRLF + o:oConnect:SQLErrorMessage() cMsg += CRLF + o:oConnect:cSQL ENDIF AlertStop( cMsg,,,64 ) RETURN o ENDIF // count rows in all Tables o:Do('TablesCount') IF lNoDbf .or. ( Select(o:cAlsTabl) > 0 .and. Select(o:cAlsStru) > 0 ) RETURN 0 ENDIF // create a list of Tables and Structures IF !hb_FileExists(o:cDbfTabl+oac:ExtDbf) .or. !hb_FileExists(o:cDbfStru+oac:ExtDbf) hb_FileDelete(o:cDbfTabl+".*") hb_FileDelete(o:cDbfStru+".*") dbCreate( o:cDbfStru, o:aDbfStru, , .T., o:cAlsStru ) dbCreate( o:cDbfTabl, o:aDbfTabl, , .T., o:cAlsTabl ) FOR EACH cTbl IN o:aTables cKod := StrZero(hb_enumindex(cTbl), 4) nCnt := o:oTables:Get(cTbl, 0) DbSelectArea( o:cAlsTabl ) // Record Tables list dbAppend() AEval({cKod, cTbl, nCnt}, {|x,n| FieldPut(n, x) }) DO EVENTS DbSelectArea( o:cAlsStru ) // Record Structure nFld := FieldPos("F_NAME") FOR EACH aFld IN o:oFields:Get(cTbl) dbAppend() FieldPut(1, cKod) AEval(aFld, {|x,n| FieldPut(n+2, x) }) cFld := Alltrim( FieldGet( nFld ) ) IF Len( cFld ) > 10 // имя в F_NAME > 10 dbDelete() ELSE FieldPut( nFld-1, cFld) ENDIF DO EVENTS NEXT NEXT DbSelectArea( o:cAlsStru ) INDEX ON &("R_CODE") TAG "CODE" GO TOP dbCloseArea() DO EVENTS DbSelectArea(o:cAlsTabl) INDEX ON &("R_CODE") TAG "CODE" GO TOP dbCloseArea() DO EVENTS ENDIF USE ( o:cDbfStru ) ALIAS ( o:cAlsStru ) NEW SHARED IF OrdCount() == 0 INDEX ON &("R_CODE") TAG "CODE" ENDIF OrdSetFocus(1) GO TOP USE ( o:cDbfTabl ) ALIAS ( o:cAlsTabl ) NEW SHARED IF OrdCount() == 0 INDEX ON &("R_CODE") TAG "CODE" ENDIF OrdSetFocus(1) GO TOP RETURN o [/pre2] для более полного понимания исп. объекта-контейнера Использование [pre2] *----------------------------------------------------------------------------* FUNCTION Main(cFile, cUser, cPass, cBclr) *----------------------------------------------------------------------------* LOCAL oTsb1, oTsb2, oac, owc, o LOCAL oFdb, cFdb, cUsr, cPsw, cBrw LOCAL oBrw1, oBrw2, nCnt1, nCnt2, nHtb LOCAL nY, nX, nH, nW, nG, oDlu, lFile LOCAL aBColor := {184, 107, 228}, aBClr LOCAL cForm := "wMain" IF !Find_In_Memory("Firebird Guardian") AlertStop( "ERROR!;Firebird program not running!;Exit program",,,64 ) QUIT ENDIF //AltD(1) // база для работы Default oac := App.Cargo cFdb := ".\FDB\Full_Receipt.fdb" cUsr := "SYSDBA" cPsw := "masterkey" oDlu := App.Object IF ( lFile := cFile != NIL ) cFdb := cFile Default cUser := cUsr ; cUsr := cUser Default cPass := cPsw ; cPsw := cPass ENDIF WaitWindow( "... Wait for the preparation to complete ...", .T. ) IF !Set_Database_For_Work(cFdb, cUsr, cPsw, lFile) // FDB из ini или default QUIT // выход ERROR message была ENDIF cFdb := oac:cBase cUsr := oac:cUsr cPsw := oac:cPsw aBClr := oac:aBClr ; Default aBClr := aBColor IF !Empty(cBclr) IF left(cBclr, 1) == "{" .and. right(cBclr, 1) == "}" aBClr := &cBclr ENDIF ENDIF oac:oFDB := oFDB_Connect( cFdb, cUsr, cPsw ) ; oFdb := oac:oFDB IF oFdb:lError ; QUIT // выход ERROR message уже была ENDIF WaitWindow() // размеры тсб 1 от dlu единиц nCnt1 := Len( oFdb:aTables ) oTsb1 := oTsb_Size( nCnt1, 4, "Normal", .F., .T., .T., .T. ) oTsb1:cForm := cForm oTsb1:oFDB := oFdb // размеры тсб 2 от dlu единиц nCnt2 := Len( oFdb:aTables ) oTsb2 := oTsb_Size( nCnt2, 9, "Normal", .F., .T., .T., .T. ) oTsb2:cForm := cForm oTsb2:oFDB := oFdb // координаты окна от тсб nG := oTsb1:nG nHtb := 32 //oDlu:H2 + nG // высота для кнопок nY := 0 nX := 0 nW := oTsb1:nW + oTsb2:nW + nG * 2 nH := oTsb1:nH + nG * 2 + nHtb ... [/pre2]

krutoff: Спасибо большое! Буду разбираться.

SergKis: krutoff пишет А нельзя в методе Read( cIniNew ) CLASS TIniData переопределить символ '#' "#" если правильно помню, так комменты, отрабатывают в hb функциях. Отдельно читаю файл от начала и с конца, для получения данных в переменных :cCommentBegin, :cCommentEnd и сам "#" не отрабатываю у себя ключи иногда делаю с "_", ваш вариант ~ так сделать _WIDTH =550,550 еще часто ключи делаю 001 = /spacetv. 002 = /ott. 003 = /ott- 004 = /myott. 005 = /mytv. 006 = /tvmedia2. 007 = /hlss.goodgame. 008 = /cdn1. 009 = /cdn01. 010 = /variant.m3u8 011 = /dmitry- 012 = /zabava- 013 = /okkotv- 014 = /cloud06. 015 = /viacomitalytest- 016 = /autopilot. 017 = /sc. ... PS. Если сейчас значение по ключу получаете через ф-ю, то можно сделать подмену (в ini иметь _Width = ...), а в ф-ии ... IF left(cKey, 1) == "#" ; cKey := "_"+subs(cKey, 2) // или простой ключ иметь cKey := subs(cKey, 2) в ini ENDIF Return App.Cargo:oIni:Get(cKey, xDef)

SergKis: krutoff Собрал пример (выше код был кусочек) с посл. версией hmg, смотрите (кому интересно) Тут (вместе с Firebird) https://TransFiles.ru/ki7ys ставлю firebird C:\Firebird_2_5 запуск сервера с иконки Target: C:\Firebird_2_5\bin\fbguard.exe -a Start in: C:\Firebird_2_5\bin пример в Advanced\_FDB_odbc demo_run.bat запускает demo.exe на несколько fdb

krutoff: Добрый день! Сделал альтернативный упрощенный вариант TiniData "для себя". Сергей, если Вам будет интересно, то, мне кажется, METHOD Read и Write можно скомбинировать с этим кодом. Да, я для себя VAR cNote2 ставлю '~' Я в ini-файле формирую структуру, названия, Tooltip для полей файла. И тут же ставлю ключи для формирования экранных и печатных форм для файла. Так сложилось, что у меня там есть одинаковые ключевые слова #LABEL, #BUTTON, #TABLE, #TABLA, #RTF и т.п. Пример: [BP73_A] 2.1. Баланс Актив: Fin-general #WIDTH =550;500 #PAGE =Баланс: Актив #LABEL =/I/N/RBP_Date() DATE =D; 8; 0;2;Дата складання звіту DATE1 =D; 8; 0;2;Станом на KATOTTG =C; 19; 0;!!(3;Коди: КАТОТТГ KOPFG =C; 10; 0;;КОПФГ KVED =C; 7; 0;);КВЕД BP_CHISP =N; 7; 0;!!;Середня кількість працівників #BUTTON =E_ADRES;Вставити адресу з титульного листа ADRES =C;254; 0;-!120;Адреса, телефон #LABEL =/I/N/RBP_Prim() FST_OZN =N; 1; 0;2D_FST;Фінансова звітність складена DATE_00 =D; 8; 0;;Дата переходу на міжнародні стандарти фінансової звітності #TABLA =Найменування показника;На початок звітного періоду;На кінець звітного періоду;На дату переходу на МСФЗ #LABEL =/B I. Необоротні активи #FORMULA =1001-1002 BP1000_03 =N; 15; 0;5(3;Нематеріальні активи: BP1000_04 =N; 15; 0;5; BP1000_00 =N; 15; 0;5; Поэтому сделал такой вариант TiniData. Он решает мои проблемы: #include "minigui.ch" #include "hbclass.ch" #include "fileio.ch" #define _NOTE_ '_NOTE_' #define _TEXT_ '_TEXT_' #define _METHOD METHOD /////////////////////////////////////////////////////////////////////////////// CLASS TIniData INHERIT THmgData /////////////////////////////////////////////////////////////////////////////// VAR cIni AS STRING INIT "" VAR cData AS STRING INIT "" VAR cBOM AS STRING INIT hb_utf8Chr( 0xFEFF ) VAR lUtf AS LOGICAL INIT .F. VAR lUtf8 AS LOGICAL INIT .F. VAR cSplit AS STRING INIT "=" VAR cNote AS STRING INIT ";" VAR cNote2 AS STRING INIT "#" VAR lNote AS LOGICAL INIT .T. METHOD New( cIni, cData, lUtf8, cSplit, cNote, cNote2 ) INLINE (::Super:New(.T.), ; ::Def( cIni, cData, lUtf8, cSplit, cNote, cNote2 ), Self) CONSTRUCTOR _METHOD Def( cIni, cData, lUtf8, cSplit, cNote, cNote2 ) _METHOD Read( cIniNew ) _METHOD Write( cFile ) METHOD ToData( cKey, cVal ) END CLASS METHOD Def( cIni, cData, lUtf8, cSplit, cNote, cNote2, lNote ) CLASS TIniData ::cIni := hb_defaultValue( cIni, ::cIni ) ::lUtf := ( Set( _SET_CODEPAGE ) == "UTF8" ) ::lUtf8 := ! EMPTY( lUtf8 ) ::cNote := hb_defaultValue( cNote, ::cNote ) ::cNote2 := hb_defaultValue( cNote2, ::cNote2 ) ::lNote := hb_defaultValue( lNote, ::lNote ) RETURN Self METHOD Read( cFile ) CLASS TIniData LOCAL hIni, cData, cLine, cKey, aKeyVal, cSec, oSec, nI LOCAL reNote, reInclude, reSection, reSplit DEFAULT cFile := ::cIni IF hb_FileExists(cFile) // Убираем атрибут ReadOnly hb_vfAttrGet( cFile, @nI ) IF hb_bitAnd(nI,0x00000001) == 1 // FILE_ATTRIBUTE_READONLY 0x00000001 hb_vfAttrSet(cFile, hb_bitAnd(nI, hb_bitNot(0x00000001))) ENDIF ENDIF IF EMPTY(hIni := hb_vfOpen(cFile, FO_READ)); RETURN SELF; ENDIF // FO_READ /* we'll read the whole file, then we'll break it in lines. */ cData := Space(hb_vfSize( hIni )) nI := hb_vfRead(hIni, @cData, hb_BLen(cData)) cData := hb_BLeft(cData, nI) hb_vfClose( hIni ) reNote := hb_regexComp( ::cNote2 + "|^[ \t]*" + ::cNote ) reSection := hb_regexComp( "[[](.*)[]]" ) reSplit := hb_regexComp( ::cSplit ) ::lUtf8 := Left(::cData, Len(::cBOM)) == ::cBOM cLine := cSec := ''; nI := 0 FOR EACH cData IN hb_ATokens(cData, .T.) // .T. - EOL IF EMPTY(cLine := RTrim(IIF(! ::lUtf .and. ::lUtf8, hb_UTF8ToStr(cData), cData))) LOOP // Skip void lines ENDIF IF EMPTY(cSec); oSec := Self; ENDIF // handling eventual comments IF ! EMPTY(aKeyVal := hb_regexSplit(reNote, cLine)) IF EMPTY(cLine := AllTrim(aKeyVal[1])) // Comment lines - NOTE IF ::lNote; oSec:Set(_NOTE_+xChar(++nI), RTrim(aKeyVal[2])); ENDIF IF LEN(aKeyVal) > 2; cLine := RTrim(aKeyVal[3]) // Строка после символа cNote2 ELSE; LOOP ENDIF ENDIF ENDIF // Is it a NEW section ? IF ! EMPTY(aKeyVal := hb_regex(reSection, cLine)) IF ! EMPTY(cLine := AllTrim(aKeyVal[2])) IF ! EMPTY(cSec); ::Set(cSec, oSec); nI := 0; ENDIF cSec := Upper(cLine); oSec := oHmgData() ENDIF // Is it a valid key ELSEIF Len( aKeyVal := hb_regexSplit(reSplit, cLine,,,1)) == 1 // Dont't Value - TEXT IF ::lNote; oSec:Set(_TEXT_+xChar(++nI), RTrim(aKeyVal[1])); ENDIF ELSE IF !EMPTY(oSec:Get(cKey := AllTrim(aKeyVal[1]))) // Уже есть такой ключ cKey += xChar(++nI) ENDIF oSec:Set(cKey, RTrim(aKeyVal[2])) ENDIF NEXT IF ! EMPTY(cSec); ::Set(cSec, oSec); ENDIF // Установим флаг "case match" для массива Hash (учитывать ли Case символа: большой/маленький ) hb_hCaseMatch( ::a_a_Key, .T. ) RETURN Self METHOD ToData( cKey, cVal ) CLASS TIniData LOCAL lUtf8 := ! ::lUtf .and. ::lUtf8 IF HB_ISOBJECT(cVal) .and. cVal:ClassName == "THMGDATA" cKey := '[' + hb_CStr(cKey) + ']' IF lUtf8; cKey := hb_StrToUtf8(cKey); ENDIF ::cData += CRLF + cKey + CRLF cVal:Eval({| val, key | ::ToData(key, val) }) ELSE IF LEFT(cKey,6) $ _NOTE_+', '+_TEXT_ .and. ::lNote // NOTE .or. TEXT cVal := LEFT(cKey,6) == _NOTE_, ::cNote,'') + cVal; cKey := '' ELSEIF LEN(cKey) < 10; cKey := PADR(cKey,10) ENDIF IF lUtf8; cKey := hb_StrToUtf8(cKey); cVal := hb_StrToUtf8(cVal); ENDIF ::cData += IIF(! EMPTY(cKey), hb_CStr(cKey)+'=','') + hb_CStr(cVal) + CRLF ENDIF RETURN .T. METHOD Write( cFile, lUtf8 ) CLASS TIniData LOCAL lRet, hFile DEFAULT cFile := ::cIni IF ! EMPTY(lUtf8); ::lUtf8 := lUtf8; ENDIF IF ! ::lUtf .AND. ::lUtf8; ::cData := ::cBOM+CRLF; ENDIF // Тут можно добавить BeginComment в ::cData ::Eval( {| cVal, cKey | ::ToData(cKey, cVal) } ) // Тут можно добавить EndComment в ::cData IF ( hFile := hb_vfOpen( cFile, FO_CREAT + FO_TRUNC + FO_WRITE + FO_EXCLUSIVE ) ) == NIL ::cData := '' RETURN .F. ENDIF lRet := hb_vfWrite( hFile, ::cData ) == hb_BLen( ::cData ) hb_vfClose( hFile ) ::cData := '' RETURN lRet

SergKis: krutoff пишет Сделал альтернативный упрощенный вариант TiniData "для себя". Вы совершенно правы THmgData можно обвешивать разным синтаксисом для работы, например, для окон сделать ф-ю [pre2] *-----------------------------------------------------------------------------* FUNCTION _oWindowDef ( oForm ) *-----------------------------------------------------------------------------* LOCAL o := oForm Default o:cName := o:FormName ; Default o:cName := o:cFormName Default o:cName := o:Name Default o:cTitle := o:Title ; Default o:cTitle := o:cCaption Default o:cTitle := o:Caption Default o:nX := o:Col ; Default o:nX := o:nCol ; Default o:nX := o:x Default o:nY := o:Row ; Default o:nY := o:nRow ; Default o:nY := o:y Default o:nW := o:Width ; Default o:nW := o:nWidth ; Default o:nW := o:w Default o:nH := o:Height ; Default o:nH := o:nHeight ; Default o:nH := o:h Default o:nVirtualHeight := o:VirtualHeight Default o:nVirtualHeight := o:VHeight ; Default o:nVirtualHeight := 0 Default o:nVirtualWidth := o:VirtualWidth Default o:nVirtualWidth := o:VWidth ; Default o:nVirtualWidth := 0 Default o:lNoMinimize := o:NoMinimize ; Default o:lNoMinimize := .F. Default o:lNoMaximize := o:NoMaximize ; Default o:lNoMaximize := .F. Default o:lNoSize := o:NoSize ; Default o:lNoSize := .F. Default o:lNoSysmenu := o:NoSysmenu ; Default o:lNoSysmenu := .F. Default o:lNoCaption := o:NoCaption ; Default o:lNoCaption := .F. Default o:lNoHScroll := o:NoHScroll ; Default o:lNoHScroll := .F. Default o:lNoVScroll := o:NoVScroll ; Default o:lNoVScroll := .F. Default o:lFocused := o:Focused ; Default o:lFocused := .F. Default o:aMinSize := o:MinSize ; Default o:aMinSize := o:aMinSize Default o:aMaxSize := o:MaxSize ; Default o:aMaxSize := o:aMaxSize Default o:aBColor := o:BackColor ; Default o:aBColor := o:aBackColor Default o:lNoShow := o:NoShow ; Default o:lNoShow := o:lHide Default o:lNoShow := o:Hide ; Default o:lNoShow := .F. Default o:lTopmost := o:Topmost ; Default o:lTopmost := .F. Default o:lPalette := o:Palette Default o:lHelpbutton := o:Helpbutton Default o:lNoAutoRelease := o:NoAutoRelease Default o:lFlashExit := o:FlashExit Default o:lMdiMain := o:MdiMain ; Default o:lMdiMain := .F. Default o:lMdi := o:Mdi ; Default o:lMdi := .F. Default o:lMain := o:Main ; Default o:lMain := .F. Default o:lChild := o:Child ; Default o:lChild := .F. Default o:lModal := o:Modal ; Default o:lModal := .F. Default o:lPanel := o:Panel ; Default o:lPanel := .F. Default o:lStandard := o:Standard ; Default o:lStandard := .F. Default o:cIcon := o:Icon Default o:cFontName := o:FontName Default o:nFontSize := o:FontSize Default o:cPanelParent := o:PanelParent Default o:cCursor := o:Cursor Default o:cNotifyIconName := o:NotifyIconName Default o:cNotifyIconTooltip := o:NotifyIconTooltip Default o:bNotifyIconLeftClick := o:NotifyIconLeftClick Default o:bNotifyIconLeftClick := o:bOnNotifyLeftClick Default o:bNotifyIconLeftClick := o:bNotifyClick Default o:bNotifyIconDblClick := o:NotifyIconDblClick Default o:bNotifyIconDblClick := o:bOnNotifyDblClick Default o:bNotifyIconDblClick := o:bNotifyDblClick Default o:bNotifyBalloonClick := o:NotifyBalloonClick Default o:bNotifyBalloonClick := o:bOnNotifyBalloonClick Default o:bNotifyBalloonClick := o:bBalloonClick Default o:bInitProcedure := o:InitProcedure Default o:bInitProcedure := o:bOnInitProcedure Default o:bInitProcedure := o:bOnInit Default o:bInitProcedure := o:bInit Default o:bReleaseProcedure := o:ReleaseProcedure Default o:bReleaseProcedure := o:bOnReleaseProcedure Default o:bReleaseProcedure := o:bOnRelease Default o:bReleaseProcedure := o:bRelease Default o:bMouseDragProcedure := o:MouseDragProcedure Default o:bMouseDragProcedure := o:bMouseDragProcedure Default o:bMouseDragProcedure := o:bOnMouseDrag Default o:bMouseDragProcedure := o:bMouseDrag Default o:bMouseDragProcedure := o:bDrag Default o:bSizeProcedure := o:SizeProcedure Default o:bSizeProcedure := o:bSizeProcedure Default o:bSizeProcedure := o:bOnSize Default o:bSizeProcedure := o:bSize Default o:bClickProcedure := o:ClickProcedure Default o:bClickProcedure := o:bClickProcedure Default o:bClickProcedure := o:bOnClick Default o:bClickProcedure := o:bClick Default o:bMouseMoveProcedure := o:MouseMoveProcedure Default o:bMouseMoveProcedure := o:bMouseMoveProcedure Default o:bMouseMoveProcedure := o:bOnMouseMove Default o:bMouseMoveProcedure := o:bMouseMove Default o:bPaintProcedure := o:PaintProcedure Default o:bPaintProcedure := o:bPaintProcedure Default o:bPaintProcedure := o:bOnPaint Default o:bPaintProcedure := o:bPaint Default o:bGotFocus := o:GotFocus Default o:bGotFocus := o:bOnGotFocus Default o:bGotFocus := o:bMouseHover Default o:bGotFocus := o:bHover Default o:bLostFocus := o:LostFocus Default o:bLostFocus := o:bOnLostFocus Default o:bLostFocus := o:bMouseLeave Default o:bLostFocus := o:bLeave Default o:bMaximizeProcedure := o:MaximizeProcedure Default o:bMaximizeProcedure := o:bOnMaximize Default o:bMaximizeProcedure := o:bMaximize Default o:bMinimizeProcedure := o:MinimizeProcedure Default o:bMinimizeProcedure := o:bOnMinimize Default o:bMinimizeProcedure := o:bMinimize Default o:bInteractiveCloseProcedure := o:InteractiveCloseProcedure Default o:bInteractiveCloseProcedure := o:bOnInteractiveClose Default o:bInteractiveCloseProcedure := o:bInteractiveClose Default o:bInteractiveCloseProcedure := o:bClose Default o:bRestoreProcedure := o:RestoreProcedure Default o:bRestoreProcedure := o:bOnRestore Default o:bRestoreProcedure := o:bRestore Default o:bMoveProcedure := o:MoveProcedure Default o:bMoveProcedure := o:bOnMove Default o:bMoveProcedure := o:bMove Default o:bDropProcedure := o:DropProcedure Default o:bDropProcedure := o:bOnDrop Default o:bDropProcedure := o:bDrop Default o:bScrollLeft := o:ScrollLeft Default o:bScrollRight := o:ScrollRight Default o:bScrollUp := o:ScrollUp Default o:bScrollDown := o:ScrollDown Default o:bHScrollBox := o:HScrollBox Default o:bVScrollBox := o:VScrollBox Default o:nClientWidth := o:ClientWidth Default o:nClientHeight := o:ClientHeight RETURN oForm [/pre2] немного поправить h_window.prg [pre2] FUNCTION _DefineWindow ( FormName, Caption, x, y, w, h, nominimize, nomaximize, ; ... LOCAL k, op ... IF FormName == NIL ... ELSEIF IsObject( FormName ) // Parameters op := _oWindowDef( FormName ) FormName := op:cName Caption := op:cTitle x := op:nX ; y := op:nY ; w := op:nW ; h := op:nH nominimize := op:lNoMinimize nomaximize := op:lNoMaximize nosize := op:lNoSize nosysmenu := op:lNoSysmenu nocaption := op:lNoCaption aMin := op:aMinSize aMax := op:aMaxSize InitProcedure := op:bInitProcedure ReleaseProcedure := op:bReleaseProcedure MouseDragProcedure := op:bMouseDragProcedure SizeProcedure := op:bSizeProcedure ClickProcedure := op:bClickProcedure MouseMoveProcedure := op:bMouseMoveProcedure aRGB := op:aBColor PaintProcedure := op:bPaintProcedure noshow := op:lNoShow topmost := op:lTopmost main := op:lMain icon := op:cIcon child := op:lChild fontname := op:cFontName fontsize := op:nFontSize NotifyIconName := op:cNotifyIconName NotifyIconTooltip := op:cNotifyIconTooltip NotifyIconLeftClick := op:bNotifyIconLeftClick GotFocus := op:bGotFocus LostFocus := op:bLostFocus VirtualHeight := op:nVirtualHeight VirtualWidth := op:nVirtualWidth scrollleft := op:bScrollLeft scrollright := op:bScrollRight scrollup := op:bScrollUp scrolldown := op:bScrollDown hscrollbox := op:bHScrollBox vscrollbox := op:bVScrollBox helpbutton := op:lHelpButton MaximizeProcedure := op:bMaximizeProcedure MinimizeProcedure := op:bMinimizeProcedure cursor := op:cCursor NoAutoRelease := op:lNoAutoRelease InteractiveCloseProcedure := op:bInteractiveCloseProcedure RestoreProcedure := op:bRestoreProcedure MoveProcedure := op:bMoveProcedure DropProcedure := op:bDropProcedure mdi := op:lMdi palette := op:lPalette NotifyIconDblClick := op:bNotifyIconDblClick cPanelParent := op:cPanelParent panel := op:lPanel NotifyBalloonClick := op:bNotifyBalloonClick clientwidth := op:nClientWidth clientheight := op:nClientHeight ENDIF ... FUNCTION _DefineModalWindow ( FormName, Caption, x, y, w, h, Parent, nosize, nosysmenu, nocaption, aMin, aMax, ; ... LOCAL k, op ... IF FormName == NIL FormName := _HMG_TempWindowName ELSEIF IsObject( FormName ) op := _oWindowDef( FormName ) // Parameters FormName := op:cName Caption := op:cTitle x := op:nX ; y := op:nY ; w := op:nW ; h := op:nH Parent := op:cParent nosize := op:lNoSize nosysmenu := op:lNoSysmenu nocaption := op:lNoCaption aMin := op:aMinSize aMax := op:aMaxSize InitProcedure := op:bInitProcedure ReleaseProcedure := op:bReleaseProcedure MouseDragProcedure := op:bMouseDragProcedure SizeProcedure := op:bSizeProcedure ClickProcedure := op:bClickProcedure MouseMoveProcedure := op:bMouseMoveProcedure aRGB := op:aBColor PaintProcedure := op:bPaintProcedure icon := op:cIcon FontName := op:cFontName FontSize := op:nFontSize GotFocus := op:bGotFocus LostFocus := op:bLostFocus VirtualHeight := op:nVirtualHeight VirtualWidth := op:nVirtualWidth scrollleft := op:bScrollLeft scrollright := op:bScrollRight scrollup := op:bScrollUp scrolldown := op:bScrollDown hscrollbox := op:bHScrollBox vscrollbox := op:bVScrollBox helpbutton := op:lHelpButton cursor := op:cCursor noshow := op:lNoShow NoAutoRelease := op:lNoAutoRelease InteractiveCloseProcedure := op:bInteractiveCloseProcedure MoveProcedure := op:bMoveProcedure DropProcedure := op:bDropProcedure clientwidth := op:nClientWidth clientheight := op:nClientHeight flashexit := op:lFlashExit ENDIF ... для h_windowsMdi.prg FUNCTION _DefineChildMDIWindow ( FormName, x, y, w, h, nominimize, nomaximize, ; ... LOCAL FormHandle , ChildIndex, op ... IF FormName == NIL FormName := _HMG_TempWindowName ELSEIF IsObject( FormName ) op := _oWindowDef( FormName ) // Parameters FormName := op:cName title := op:cTitle x := op:nX ; y := op:nY ; w := op:nW ; h := op:nH nominimize := op:lNoMinimize nomaximize := op:lNoMaximize nocaption := op:lNoCaption novscroll := op:lNoVScroll nohscroll := op:lNoHScroll FontName := op:cFontName FontSize := op:nFontSize initprocedure := op:bInitProcedure ReleaseProcedure := op:bReleaseProcedure ClickProcedure := op:bClickProcedure GotFocus := op:bGotFocus LostFocus := op:bLostFocus SizeProcedure := op:bSizeProcedure maximizeprocedure := op:bMaximizeProcedure minimizeprocedure := op:bMinimizeProcedure focused := op:lFocused cursor := op:cCursor InteractiveCloseProcedure := op:bInteractiveCloseProcedure MouseMoveProcedure := op:bMouseMoveProcedure ENDIF ... [/pre2] и ваши окна будут работать от данных ini\cfg файлов, созданных и прочитанных в THmgData контейнер Контролы можно так же ввести в такую схему работы

krutoff: В методе METHOD Read я соединил функции hb_iniReadStr, hb_iniFileLow и hb_iniStringLow. В блоке hb_iniStringLow добавил доп. обработку и вставку комментов и строк без разделителя. METHOD Write тоже обрабатывает все ваши переменные a_a_Key класа THmgData без переходных hash-переменных. Так, что если заинтересует, предлагаю применить. В последней версии блок проверки на ReadOnly файл переставил в METHOD Write.

SergKis: krutoff пишет Так, что если заинтересует, предлагаю применить Это скорее к Григорию. Со времен clipper в ini файлах использовал в стандарте # и ; как комментарии, даже :Write() не использовал - хватало. Ключ, начинающийся с #KeyName, использовал в VO, отказался быстро, т.к. исп. его, ключ, как имена переменных (правила). То что есть мне хватает выше головы, причем, файлы ini\cfg у меня всегда в Utf8, для других данных сохранение может быть в json (htm, xml, js) или hb_valtoexp(...) и могут быть подчитаны при чтении ini\cfg блоком кода или ф-ей типа (в ini\cfg) xVal1 := {|| myRead(".\wrk\имя файла") }



полная версия страницы