Решил поделиться опытом, может кому пригодиться.
В МиниГуи постоянно возникает нужда вернуть данные с формы.
Есть много вариантов, но мне понравился самый последний, который помог сделать Сергей.
Задача - есть форма, на ней много разных данных и после закрытия формы нужно вернуть МАССИВ (можно и json).
Вот вариант с использованием контейнера на самой форме !
Контейнер можно создавать на любом объекте, очень удобно, особенно на кнопке.
Схема такая:
// заполняется для формы в начале проги
oFrm2 := oHmgData()
oFrm2:aType := { "S" , "S" , "D" , "N" , "C" , "A" , "M" }
oFrm2:aName := { "Application type", "Condition" , "Application deadline", "Payment amount", "Comment" , "Print application", "Memo-field" }
oFrm2:aFor := { {"tipza","Ktipza","tipza",2} , {"Works","KWorks","Works",2} , {"D"}, {"N"}, {"C"} , {"Master","Manager","Warehouse"}, {"M"} }
oFrm2:aFld := {"Ktipza","KWorks","DatePere","SumPlata","Dispetch","KAdres1" ,"mAktVip"} // поля записи в базу
oFrm2:aIcon := {"" ,"" ,"" ,"" ,"" ,"iPrint32", "" } // иконки в контекстное меню
oFrm2:aBClr := GREEN // цвет фона формы
oFrm2:aFClr := BLUE // цвет текста формы
aVal13 - заполняется выше из oFrm2:aFld
aRet := {} // всегда массив - пусто, значит отказ от ввода
aRet1 := aVal13 // что пришло в функцию
aName := oFrm2:aName
cType := oFrm2:aType
aXFor := oFrm2:aFor
a1One := массив данных из dbf-справочников: {"tipza","Ktipza","tipza",2} , {"Works","KWorks","Works",2}
aBtnBClr := { {225,225,225}, GRAY }
aBtnFClr := { RED , WHITE }
DEFINE WINDOW &cForm ....
ON INIT ( This.Label_0.Setfocus, DoEvents() )
This.Cargo := oHmgData() ; owc := This.Cargo // создаём контейнер на форме - пустой
owc:nFor := 0 // нажата button/getbox/combo
owc:aRet1 := aRet1 // массив значений для правки помещаем в контейнер окна
owc:aBClr := This.BackColor // можно много данных сохранить в контейнер,
// и доставать оттуда в нужном месте кода программы
@ 0, 0 LABEL Label_0 VALUE "" WIDTH 5 HEIGHT 5 TRANSPARENT
FOR nI := 1 TO LEN(aName)
cType := aType[nI]
cText := aName[nI] + ":"
cObj := "Lbl_" + STRZERO(nI,2)
@ nY, nX LABEL &cObj VALUE cText WIDTH nWText HEIGHT nHText ;
BOLD FONTCOLOR aFClr RIGHTALIGN TRANSPARENT
nCol := nX + This.&(cObj).Width + nG/2
cObj := "GBox_" + STRZERO(nI,2)
IF cType == "C"
@ nY, nCol GETBOX &cObj VALUE aRet1[nI] BOLD ;
WIDTH nWGBox HEIGHT nHText ;
ON CHANGE {|| ThisWindow.Cargo:aRet1[ This.Cargo ] := This.Value } // правим массив в контейнере формы
This.&(cObj).Cargo := nI
ELSEIF cType == "N"
@ nY, nCol GETBOX &cObj VALUE aRet1[nI] BOLD ;
WIDTH nWGBox HEIGHT nHText ;
ON CHANGE {|| ThisWindow.Cargo:aRet1[ This.Cargo ] := This.Value } // правим массив в контейнере формы
This.&(cObj).Alignment := "LEFT" // "CENTER" or "RIGHT"
This.&(cObj).Cargo := nI
ELSEIF cType == "D"
dDate := aRet1[nI]
@ nY, nCol DATEPICKER &cObj VALUE dDate WIDTH nWGBox HEIGHT nHText ;
DATEFORMAT "dd'.'MMMM' 'yyyy" SHOWNONE BOLD ;
ON CHANGE {|| ThisWindow.Cargo:aRet1[ This.Cargo ] := This.Value } // правим массив в контейнере формы
This.&(cObj).Cargo := nI
ELSEIF cType == "A" // выбор из массива по кнопке
aDim := aXFor[nI] // все значения из массива - {"Master","Manager","Warehouse"}
cImg := aIcon[nI] // иконку передать в контекстное меню
IF aRet1[nI] == 0 ; cCap := "- - -"
ELSEIF aRet1[nI] <= LEN(aDim) ; cCap := aDim[aRet1[nI]]
ELSE ; cCap := "??? code: " + HB_NtoS(aRet1[nI])
ENDIF
cObj := "Btn_" + STRZERO(nI,2)
@ nY, nCol BUTTONEX &cObj WIDTH nWGBox HEIGHT nHText CAPTION cCap ;
PICTURE "ArrowDown20" NOXPSTYLE HANDCURSOR NOTABSTOP LEFTTEXT ;
FONTCOLOR BLACK BACKCOLOR aBtnClr[1] BOLD ;
ON MOUSEHOVER ( This.Fontcolor := This.Cargo:aFClr[2], This.Backcolor := This.Cargo:aBClr[2] ) ;
ON MOUSELEAVE ( This.Fontcolor := This.Cargo:aFClr[1], This.Backcolor := This.Cargo:aBClr[1] ) ;
ACTION {| | This.Enabled := .F., _wPost(This.Cargo:nPost, ThisWindow.Name, This.Name) } ;
ON INIT {|o| This.Cargo := oHmgData(), o := This.Cargo ,;
o:nBtn := nI ,; // номер нажатой кнопки
o:nPost := 10 ,; // номер события
o:cBtn := This.Name ,;
o:cCapt := This.Caption ,;
o:aBClr := This.BackColor ,;
o:nY := This.Row ,;
o:nX := This.Col ,;
o:aFClr := aBtnFClr ,; // 2 цвета для текста кнопки
o:aBClr := aBtnBClr ,; // 2 цвета для фона кнопки
o:cTxt := cCap ,;
o:aTxt := aDim ,;
o:cIco := cImg }
Btn_MaxTxtWidth(cForm, cObj) // максимальный размер надписи с пробелами
//? _o2log(This.&(cObj).Cargo, 27, ProcNL() + " This.&("+cObj+").Cargo => ", .T. ) // проверка
//ACTION {|| This.Enabled := .F., ; // можно и так проверить
// _LogFile(.T.,"$$$$$", This.Name, This.Cargo, ThisWindow.Name), ;
// _wPost(This.Cargo:nPost, ThisWindow.Name, This.Name) } ;
ELSEIF cType == "S"
aDim := aArCmb[nI]
cObj := "CmBox_" + STRZERO(nI,2)
@ nY, nCol COMBOBOXEX &cObj BOLD WIDTH nWGBox HEIGHT 300 ;
ITEMS aDim VALUE a1One[nI] ;
ON CHANGE {|| ThisWindow.Cargo:aRet1[ This.Cargo ] := This.Value ,; // правим массив в контейнере формы
This.Label_0.Setfocus }
This.&(cObj).Cargo := nI
ELSEIF cType == "M"
cObj := "EditBox_" + STRZERO(nI,2)
@ nY, nCol EDITBOX &cObj WIDTH nWGBox HEIGHT nHText * 4 ;
VALUE aRet1[nI] BACKCOLOR {240, 240, 240} NOTABSTOP ;
ON CHANGE {|| ThisWindow.Cargo:aRet1[ This.Cargo ] := This.Value } // правим массив в контейнере формы
This.&(cObj).Cargo := nI
ELSE
cMsg := "Error ! cType == ??? [" + cType + "] !"
MsgDebug(cMsg, cType, nI, cText)
ENDIF
nY += This.&(cObj).ClientHeight + nG
NEXT
/////////////////////// кнопки на форме ////////////////////////////////
nY := nH - nG - nHBtn
nX := ( nW - nWBtn * 2 - nG ) / 2
aIco1 := { "iMg_Ok48x1" , "iMg_Ok48x2" }
aIco2 := { "iMg_Cancel48x1", "iMg_Cancel48x2" }
@ nY, nX BUTTONEX Btn_Ok WIDTH nWBtn HEIGHT nHBtn CAPTION 'Save' ;
ICON aIco1[1] NOXPSTYLE HANDCURSOR NOTABSTOP ;
FONTCOLOR aBtnFClr[1] FONT cBtnFont SIZE nBtnFSize BOLD ;
BACKCOLOR aGrOver GRADIENTFILL aGrFill ;
ON MOUSEHOVER ( This.Icon := aIco1[2] , ;
This.Fontcolor := aBtnFClr[2], ;
This.GradientFill := aGrFill ) ;
ON MOUSELEAVE ( This.Icon := aIco1[1] , ;
This.Fontcolor := aBtnFClr[1], ;
This.GradientOver := aGrOver ) ;
ACTION {|| _wPost(90 ,, This.Name) }
nX += This.Btn_Ok.Width + nG
@ nY, nX BUTTONEX Btn_Esc WIDTH nWBtn HEIGHT nHBtn CAPTION 'Cancel ' ;
ICON aIco2[1] NOXPSTYLE HANDCURSOR NOTABSTOP ;
FONTCOLOR aBtnFClr[1] FONT cBtnFont SIZE nBtnFSize BOLD ;
BACKCOLOR aGrOver GRADIENTFILL aGrFill ;
ON MOUSEHOVER ( This.Icon := aIco2[2], ;
This.Fontcolor := aBtnFClr[2], ;
This.GradientFill := aGrFill ) ;
ON MOUSELEAVE ( This.Icon := aIco2[1], ;
This.Fontcolor := aBtnFClr[1], ;
This.GradientOver := aGrOver ) ;
ACTION {|| _wPost(98 ,, This.Name) }
ON KEY ESCAPE ACTION _wPost(98)
IF !lMemo
ON KEY RETURN ACTION _wPost(90)
ENDIF
(This.Object):Event( 10, {|ow,ky,cn| // выбор из массива по кнопке
Local aTxt, cImg, aRet, cCapt, ocBtn, nI, nRet
Local owc := ow:Cargo // cargo окна
ocBtn := This.&(cn).Cargo // cargo нажатой кнопки
_SetThisFormInfo(ow) // save This среду окна ow
aTxt := ocBtn:aTxt
cImg := ocBtn:cIco // иконку передать в контекстное меню
nRet := ocBtn:nRet // первоначальное значение
nI := ocBtn:nBtn // номер нажатой кнопки
owc:nFor := nI
cCapt := ocBtn:cCapt
//MsgDebug(ow:Name, ky, cn, ocBtn, "nI=",nI,owc:aRet1)
aRet := Btn_ContexMenu(ow, ocBtn:nY, ocBtn:nX, aTxt, cImg, .T.) // контекстное меню
IF LEN(aRet) > 0
owc:aRet1[nI] := aRet[1] // ВОТ ТАК НУЖНО !!! -->> правим массив в контейнере формы
ocBtn:cCapt := aRet[2]
cCapt := aRet[2]
ENDIF
_SetThisFormInfo() // restore This среду окна ow
This.&(cn).Enabled := .T.
This.&(cn).Caption := cCapt // возврат на кнопку
Btn_MaxTxtWidth(ow:Name, cn) // максимальный размер надписи с пробелами
ow:Setfocus('Label_0')
DO EVENTS
ky := cn
Return Nil
} )
(This.Object):Event( 90, {|ow,ky,cn| // сохранить данные
Local aRet2, owc := ow:Cargo
aRet2 := owc:aRet1 // перепишем массив значений
? "### Save", ProcNL(), HB_ValToExp(aRet2) // манипуляции с aRet2
aRet := {aRet2,cVal}
_wPost(99,ow)
ky := cn
Return Nil
} )
(This.Object):Event( 98, {|ow| aRet := {}, _wPost(99,ow) } )
(This.Object):Event( 99, {|ow| ow:Release() } )
END WINDOW
ACTIVATE WINDOW &cForm
RETURN aRet