Mřížka, ach ta mřížka - Dynamické generování mřížky

Mřížka patří mezi nejproklínanější a nejvelebovanější třídu ve VFP. Právě jednoduchost s jakou se dají vytvářet zdánlivě složité mřížky vizuálním návrhem, způsobí rozčarování při programovém vytváření mřížky.
Návrh mřížky by se dal dělit dle tří kategorií podle obtížnosti způsobu návrhu.

Návrh začátečníků

Mřížka je vizuálně navržena přímo na formuláři. Formulář si zdroj dat otevírá sám pomocí integrovaného DataEnvironmentu. Problémy s návrhem nejsou.

Návrh pokročilých

Mřížka je vizuálně navržena přímo na formuláři či třídě formuláře, popřípadě je vytvořena odvozená třída mřížky již s předvytvořenými sloupcemi. Formulář si zdroj dat otevírá sám, nebo je zdroj dat otevřen v události Load() na formuláři. Zde již mohou nastat drobné problémy, neboť je opravdu nutné zajistit, aby byl přístupný daný alias, který je uveden ve vlastnosti RecordSource na mřížce, dříve než proběhne inicilizace mřížky tj. dříve než proběhne událost Init() mřížky. Pokud tomu tak není, dojde k tomu, že obsah polí neodpovídá popisu polí, či dokonce přibyla další pole.
VFP při inicializaci mřížky postupuje takto:

Návrh expertů

Sem patří dynamické vytváření mřížky za běhu programu (ať jednou či vícekrát) na základě zdroje dat, či vlastních informací, přičemž zdroj dat může být pokaždé jiný. Sloupce jsou vytvářeny dle základní třídy Column či odvozených tříd.
Základní pravidla při vytváření sloupců v mřížce:
Zdrojový kód:
loGrid.RecordSource=Můj_Zdroj_Dat && Zdroj dat
FOR lii=loGrid.ColumnCount TO 1 STEP -1
    loGrid.DeleteColumn(lii) && Odstraň sloupec
NEXT
FOR lii=1 TO Počet_Sloupců
    loGrid.AddObject("Column"+LTRIM(STR(lii,11)),Název_mé_třídy_sloupce) && Přidej sloupec
    WITH loGrid.Columns(lii)
    *...
    *...
    ENDWITH
NEXT

Samotný návrh třídy sloupce lze umístit pouze do PRG souboru.
Zdrojový kód:
DEFINE CLASS _MyColumn AS Column
   ADD OBJECT Header1 AS Header
   ADD OBJECT Text1   AS Textbox

   FontName="MS Sans Serif"
   FontSize=8

   Text1.Margin=0    
   Text1.BorderStyle=0   && Bez okraje
   Text1.FontName="MS Sans Serif"
   Text1.FontSize=8

   Header1.FontName="MS Sans Serif"
   Header1.FontSize=8

   BackColor=RGB(255,255,255)  && Barva pozadí sloupce
   ForeColor=RGB(000,000,000)  && Barva písma sloupce
   ReadOnly=.T.

   PROCEDURE Show
      STORE .T. TO This.Visible,This.Text1.Visible && Ukaž textbox
   ENDPROC
ENDDEFINE
VFP je bohužel u mřížky velmi citlivá, pokud ji uzavřeme zdroj dat. Hodil by se spíše výraz "Velmi zmatená" a podobně. Proto je nutné předtím, než uzavřeme zdroj dat, mřížku vyčistit.
Zdrojový kód:
FOR lii=loGrid.ColumnCount TO 1 STEP -1
    loGrid.DeleteColumn(lii) && Odstraň sloupec
NEXT
loGrid.RecordSource="" && Vymaž zdroj dat
Jednodušší variantou je, pokud je mřížka vytvořena pouze jednou (zdroj dat se sice mění, ale jde o zdroje se stejnou strukturou dat) a podle potřeby je obnovován. Generování mřížky je stejné jako v předchozím případě. Rozdíl je při uzavírání zdroje dat. Mřížka se nečistí, pouze se využije nedokumentovaného chování mřížky (Softwarový QUAS 99/28 s.16/17). Tento "fígl" zajistí, že si grid zapamatuje informace o sloupcích (bohužel ne všechny).
Vytvořme si ve vlastní třídě mřížky metodu SaveEnv() (uložení informací o sloupcích) a LoadEnv() (načtení informací sloupcích). Také budeme potřebovat založit matici aColumnGrid[] jako úložiště informací.
Metoda grid::SaveEnv() - Zdrojový kód:
LOCAL lii
DIME This.aColumnGrid(This.ColumnCount,3)
FOR lii=This.ColumnCount TO 1 STEP -1
    This.aColumnGrid(lii,1)=This.Columns(lii).Width && Zapamatuj si šířku
    This.aColumnGrid(lii,2)=This.Columns(lii).ColumnOrder && Zapamatuj si pořadí
    This.aColumnGrid(lii,3)=This.Columns(lii).ControlSource && Zapamatuj si zdroj dat
NEXT
Metoda grid::LoadEnv() - Zdrojový kód:
LOCAL lii,loCol
FOR lii=This.ColumnCount TO 1 STEP -1
    loCol=This.Columns(lii)
    loCol.Width=This.aColumnGrid(lii,1) && Nastav šířku šířku
    loCol.ColumnOrder=This.aColumnGrid(lii,2) && Nastav pořadí
    loCol.ControlSource=This.aColumnGrid(lii,3) && Nastav zdroj dat
NEXT
Ukázka:
loGrid.SaveEnv() && Ulož nastavení sloupců
loGrid.RecordSource="" && Vymaž zdroj dat
* Tady se může zdroj dat uzavřít, otevřít jiný podobný atd.
loGrid.LoadEnv() && Načti nastavení sloupců
Ke snadnějšímu dynamickému generování mřížky se hodí metody Clear() a Generate(). Metoda Clear() slouží pro korektní likvidaci sloupců (i vymazání zdroje dat ) a Generate() pro vygenerování n sloupců určité třídy (maže původní obsah mřížky) a vlastnost ColumnClass (název třídy sloupce pro generování). (Od VFP 8.0 a výše má mřížka vlastnosti MemberClass a MemberClassLibrary které ulehčují generování mřížky, ale o tom až v některém z dalších dílů.)
Metoda grid::Clear() - zdrojový kód:
LPARAM llClearResource
* llClearResource - Příznak zda se má vymazat vlast. RecordSource
LOCAL lii,llLS
llLS=Thisform.LockScreen
Thisform.LockScreen=.T.
* Nyní smaž všechny sloupce
FOR lii=This.ColumnCount TO 1 STEP -1
    This.RemoveObject(This.Columns(lii).Name)
NEXT
IF !EMPTY(llClearResource)
   This.RecordSource="" && Vymaž ještě zdroj dat
ENDIF
Thisform.LockScreen=llLS
Jako parametr je přijímána proměnná typu Boolean. Vytvoří se objekt pro zablokování překreslování formuláře. Postupně se mažou sloupce (odzadu). Pokud je předaný parametr .T. , vymaže se i vlastnost RecordSource.
Metoda grid::Generate() - zdrojový kód:
LPARAM lcAlias, liColumnCount
* Pokud zadáme lcAlias="" a liColumns=0, mřížka pouze vymaže všechny své sloupce.
IF EMPTY(lcAlias) AND !EMPTY(liColumnCount) && Pokud nejsou správně parametry
   RETURN .F.
ENDIF
IF EMPTY(liColumnCount)
   liColumnCount=0 && Pak vypni generování sloupců
ENDIF

LOCAL lii,llLS
llLS=Thisform.LockScreen
Thisform.LockScreen=.T.
This.ColumnCount=0
This.RecordSource=lcAlias && Zapiš zdroj dat
This.Clear() && Smaž mřížku
IF liColumnCount>0
   FOR lii=1 TO liColumnCount
       This.AddObject("Column"+LTRIM(STR(lii,6)),This.ColumnClass)
   NEXT
   This.SetAll("Visible",.T.) && Zobraz všechny objekty
ENDIF
This.FontName="MS Sans Serif" && Nastavení výchozího fontu
This.FontSize=8
Thisform.LockScreen=llLS
RETURN .T.
Jako parametr je přijímána proměnná typu String (zdrojový alias) a Integer (počet sloupců). Nastaví se počet sloupců na 0, zdrojový alias a zavolá se metoda Clear() bez parametru. Potom se přidají sloupce podle třídy, jejíž název je uložen ve vlastnosti ColumnClass. Pak se už jen nastaví vlastnost Visible všech objektu na .T., název a velikost fontu celé mřížky.