Většina z vás patrně ví, jak je snadné přetřídit data v Gridu (mřížce) kliknutím na nadpis sloupce pouhým napsáním příkazu SET ORDER TO ... v Click() metodě Headeru (hlavičky).
Velkou nevýhodou tohoto postupu ale je, že řádek na kterém právě jsme, odroluje a uživatel se najednou dívá na zcela jiná data než před kliknutím. Pokud se chceme této nepříjemnosti vyhnout, je třeba k tomuto problému přistoupit systematicky. V Click() metodě sloupce zavoláme metodu Reorder() přidanou k výchozímu Gridu (k třídě):
* Tento objekt(hlavička).Otec(sloupec).Otec(otec sloupce - grid) This.Parent.Parent.Reorder(This.Parent,.T.) * Obsah metody Reorder() * Význam parametrů: * poCol - reference (odkaz) na sloupec, podle kterého třídíme * plAscending - .T. = vzestupně, .F. = sestupně LPARAMETER poCol,plAscending LOCAL i, j, llLockScreen, lnRecno, lnRelativeRow, lnDirection, lcDescending, lcTag * Zapamatuje me si, na kterém RELATIVNÍM ŘÁDKU NA OBRAZOVCE jsme lnRelativeRow = poCol.Parent.RelativeRow lcDescending = IIF(! plAscending, "descending", "ascending") * Do lcTag uložíme jméno položky, podle které chceme třídit lcTag = NORMALIZE(poCol.ControlSource) * Zdroj může být ve tvaru TABULKA.POLOŽKA * takže je nutné aliasy odstranit lcTag=STRTRAN(lcTag,NORMALIZE(poCol.Parent.RecordSource)+".","") * Zjišťujeme, zda existuje tag, který bychom mohli použít i = 1 DO WHILE NOT EMPTY(TAG(i)) AND NOT NORMALIZE(KEY(i))==lcTag i = i+1 ENDDO * Pokud jsem nenašli potřebný index, pokusíme se najít takový, * který nejvíce odpovídá při porovnání zleva IF EMPTY(TAG(i)) i = 1 DO WHILE NOT EMPTY(TAG(i)) AND NOT LEFT(NORMALIZE(KEY(i)),LEN(lcTag))==lcTag i = i+1 ENDDO ENDIF IF !EMPTY(TAG(i)) * Takový tag existuje: * Vypneme zobrazení, aby obrazovka zbytečně neblikala llLockScreen = Thisform.LockScreen Thisform.LockScreen = .T. * Zapamatujeme si větu, na které jsme lnRecno=RECNO() * Nastavíme třídění SET ORDER TO (TAG(i)) &lcDescending. * Překreslíme Grid (poprvé :)) poCol.Parent.Refresh() * Skočíme zpátky na původní větu GO lnRecno * Překreslíme Grid (podruhé :):)) poCol.Parent.Refresh() * Pokud nejsme na stejném řádku jako na začátku IF (lnRelativeRow != poCol.Parent.RelativeRow) * Určíme počet řádků, o které se musíme posunout... lnDirection = IIF(lnRelativeRow>poCol.Parent.RelativeRow,0,1) j = ABS(lnRelativeRow - poCol.Parent.RelativeRow) * ... a posuneme se FOR i = 1 TO j poCol.Parent.DoScroll(lnDirection) ENDFOR ENDIF * Překreslíme Grid (potřetí :):):)) poCol.Parent.Refresh() * A uvedeme zobrazení do původního stavu Thisform.LockScreen = llLockScreen ELSE * Nenašli jsme tag, který bychom mohli použít WAIT WINDOW "Data nelze přetřídit..." NOWAIT TIMEOUT 5 ENDIF
A to je vše. Zdraví vás
Milan Kosina, kosina@vol.cz
Původní zdrojový kód je v SOFTWAROVÝm QUASu 2000/33 na stránkách 17/18.
Zdrojový kód metody lze stáhnout zde.
Součástí zdrojového programu jsou dvě procedury:
Reorder() | je totožná s výše uvedeným zdrojovým kódem |
ReorderEx() | je totožná s výše uvedeným zdrojovým kódem s drobnou úpravou; jako první parametr se dá poslat název tagu |
Pozn. přepis.: | Původní zdrojový kód v sobě obsahoval dvě drobné chybičky. Navíc nepočítal s tím, že index, ale i zdroj sloupce, může být složen z více položek. Nyní když není nalezen index, který plně odpovídá zdroji dat sloupce, pak se najde první index, který zdroji dat sloupce nejvíce odpovídá při porovnání zleva. Je zde také zapomenuto, že událost Click() hlavičky sloupce se vyvolá i když uživatel roztáhne sloupec (tím dojde i k nechtěnému vyvolání přetřídění). Tomu lze zabránit přídáním metody SplitLineHitTest() do třídy gridu, která zjišťuje, zda je uživatel nad pravým okrajem sloupce. Vlastní kód metody je v článku Grid - část první (dokončení) (až na konci). Před zavoláním metody Reorder() by se měla volat metoda SplitLineHitTest() s parametrem This (tento sloupec). Pokud metoda vrátí .F. je ukazatel myši mimo pravý okraj sloupce a může se tedy volat metoda Reorder(). |
|
Pozn. přepis.: | Pokud vám to nebude fungovat, pak vězte, že váš návrh tříd je poněkud prohnilý. (Nezoufejte, nejste sami. V době, kdy čtete tento článek, pravděpodobně stále hledám proč to v mým frameworku nefunguje.) |