Grids Reference Page/pl

From Lazarus wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) polski (pl) русский (ru)

Strona referencyjna siatek Grid

Intencje

Ten tekst będzie próbą pokazania użytkownikowi niektórych aspektów komponentów siatek (grids) w Lazarusie. Ma również służyć jako przewodnik dla użytkowników, którzy nigdy dotąd nie używali komponentów siatek (ponieważ doświadczeni użytkownicy zazwyczaj potrzebują jedynie informacji dotyczących nowych funkcji). W niniejszym tekście postaram się zatem osiągnąć następujące cele:

  1. Przedstawić komponenty siatki osobom z niewielkim lub żadnym doświadczeniem w Delphi.
  2. Udokumentować różnice w odniesieniu do komponentów siatek Delphi.
  3. Udokumentować nową funkcjonalność w siatkach Lazarusa.
  4. Utworzyć referencje i przykłady dla tych komponentów.

Wprowadzenie

Siatka (Grid) to komponent, który umożliwia wyświetlanie danych w formacie tabelarycznym. Najbardziej oczywistą cechą siatek jest to, że składają się one z komórek tworzących rzędy i kolumny, podobnie jak w arkuszu kalkulacyjnym.

Ilość typów informacji, które można wyświetlić w siatce, jest różna i zależy głównie od tego, co użytkownik chce pokazać. Ogólnie informacje te składają się z tekstów, kolorów, obrazów lub kombinacji tych trzech.

Biorąc pod uwagę ogromną różnorodność informacji, które można przedstawić, istnieje szereg siatek, których celem jest ułatwienie użytkownikowi pokazania określonych rodzajów informacji. Na przykład istnieje siatka przeznaczona do wyświetlania tekstu: StringGrid. Dokumentację dla tej siatki można znaleźć tutaj

Drzewo dziedziczenia

                     TCustomControl
                             |
                             |
                        TCustomGrid
                             |
               +-------------+------------+
               |                          |
         TCustomDrawGrid             TCustomDbGrid
               |                          |
      +--------+--------+                 |
      |                 |              TDBGrid
  TDrawGrid      TCustomStringGrid                
                        |
                        |
                   TStringGrid

Pierwszy przykład

Ponieważ jednym z celów tej strony jest pomoc osobom z niewielką lub żadną wcześniejszą wiedzą o Lazarusie, zróbmy wprowadzający przykład użycia siatek. Dlaczego nie, stwórzmy tradycyjny przykład „Witaj Świecie!” (ang. "Hello World") za pomocą komponentu TStringGrid.

  1. Stwórz nową aplikację.
    • Z menu głównego wybierz: Projekt->Nowy projekt...
    • W oknie dialogowym Utwórz nowy projekt wybierz Aplikacja i naciśnij „OK”
    • Zostanie wyświetlony nowy pusty formularz.
  2. Umieść siatkę (grid) na formularzu
    • Z palety komponentów wybierz zakładkę „Additional”
    • Kliknij ikonę TStringGrid tstringgrid.png
    • Kliknij formularz w lewym górnym rogu. Pojawi się nowa pusta siatka.
  3. Umieść przycisk na formularzu
    • Z palety komponentów wybierz zakładkę „Standard”
    • Kliknij ikonę TButton tbutton.png
    • Kliknij na pusty obszar formularza. Pojawi się nowy przycisk.

Kliknij dwukrotnie przycisk z kroku 3 i zapisz następujący kod w module obsługi przycisku kliknięcia:

    • StringGrid1.Cells[1,1] := 'Witaj Świecie!';
      
  1. Uruchom program, klikając ikonę odtwarzania menu run.png
    • po naciśnięciu przycisku Button1 w komórce w kolumnie 1 i wierszu 1 powinien pojawić się tekst „Witaj Świecie!”. (zwróć uwagę, że indeksy lewej kolumny i górnego wiersza są równe 0)

Różnice pomiędzy komponentami siatki Lazarusa i Delphi

Obecne elementy siatek różnią się od siatek Delphi na kilka sposobów. Jest to spowodowane głównie tym, że kiedy po raz pierwszy opracowano siatki dla Lazarusa, były one tworzone od zera bez żadnych prób uczynienia ich w pełni kompatybilnymi z Delphi.

Na późniejszym etapie kompatybilność z siatkami Delphi stała się pożądanym celem, a siatki Lazarus zaczęły być bardziej zgodne z interfejsem sieci Delphi. Jednak nawet to zostało zrobione bez próby dopasowania każdej właściwości lub metody siatki Lazarusa do swojego odpowiednika w Delphi. Ponadto (ponieważ wewnętrzne elementy siatki Lazarusa bardzo różnią się od wewnętrznych elementów siatki Delphi) niektóre funkcje Delphi nie są dostępne lub muszą być emulowane w inny sposób w siatce Lazarusa niż w przypadku siatki Delphi. Osiągnęliśmy większą kompatybilność z Delphi w miarę ewolucji siatek Lazarusa i jest to pożądane.

Różnice

Znane różnice wymieniono poniżej (kolejność nie ma znaczenia).

  • Edytor komórek (Cell Editor)
  • Zachowanie podczas projektowania
  • Pewne różnice występują podczas rysowania komórek, zobacz sekcję Dostosowywanie siatek.

Nowe funkcje

  • Kolumny
  • Zdarzenia
  • Edytor siatki (Grid Editor)

Sposoby na to, by siatka Lazarus była bardziej zgodna z Delphi

Oto lista właściwości i korekt, które mogą być wykonane w celu dostosowania wyglądu lub zachowania komponentów grids Lazarusa do tych z Delphi. Korekty te odnoszą się do nowo utworzonej siatki. Wpisy z etykietą [Kod] należy wykonać w kodzie, a z etykietą [Projekt] można zmieniać w czasie projektowania.

Możesz sprawić, by siatka Lazarusa wyglądała i zachowywała się tak, jak jej odpowiednik w Delphi. Poniżej wymienione są ustawienia właściwości, które pozwolą to osiągnąć. Te dostosowania są oparte na nowo utworzonej siatce. Wpisy oznaczone jako [Kod] należy ustawić w kodzie, wpisy [Projekt] można zmienić w czasie projektowania.

  • [Projekt] TitleStyle := tsStandard;
  • [Projekt] DefaultRowHeight := 24;
  • [Kod] EditorBorderStyle := bsNone; //to może działać tylko w Windows
  • [Kod] UseXORFeatures := true;
  • [Kod] AllowOutBoundEvents := False; //rewizja SVN r10992 lub nowsza
  • [Kod] FastEditing := False; //obsługiwane w dbgrid. StringGrid wymaga wersji SVN r10992 lub nowszej
  • [Projekt] AutoAdvance := aaNone;

Charakterystyka siatek

Informacja

Punktem wyjścia dla referencji o TCustomGrid, TDrawGrid, TCustomDrawGrid, TCustomStringGrid i TStringGrid jest referencje modułu Grids.pas

Natomiast dla TCustomDBGrid i TDBgrid jest referencje modułu DBGrids.pas

Zazwyczaj jakichkolwiek informacje o komponentach grids dla Delphi powinny pomóc nam także w Lazarusie (ale nie zapominajmy o tych kilku różnicach pomiędzy Delphi i Lazarusem, które są udokumentowane); przy czym traktuj takie dane jako tymczasowe źródło informacji, które nie zawsze będą działały tak samo jak w Delphi.

TODO: Dalsza część tego rozdziału zniknie, a jego zawartość zostanie przeniesiona do referencje modułu Grids.pas

TCustomGrid

Wszystko zobaczysz w: Referencje TCustomGrid

Właściwość AllowOutboundEvents

Właściwość chroniona w klasie TCustomGrid oraz publiczna w klasie TCustomDrawGrid i klasach potomnych. Zwykle, gdy użytkownik kliknie punkt nad pustą przestrzenią za komórkami (na przykład, jeśli siatka ma trzy wiersze, ale użytkownik kliknie wyimaginowany czwarty wiersz), komórka, w której aktualnie znajduje się fokus, przesunie się do komórki najbliższej punktu, który właśnie kliknął. Nazywamy to wydarzeniem wychodzącym. Wartość domyślna to True, ponieważ tak właśnie działa siatka od samego początku. Ta właściwość została dodana, aby symulować zachowanie Delphi, gdy zdarzenia wychodzące nie są dostępne, więc aby umożliwić zgodność z Delphi, ustaw tę właściwość na False.

Właściwość Columns

Lazarus zawiera właściwość columns w siatkach TStringGrid i TDrawGrid. Ta właściwość dodaje to, co nazywamy kolumnami niestandardowymi. Kolumny niestandardowe to zbiór obiektów, które przechowują właściwości, które mają zastosowanie do całych kolumn, na przykład tytuły kolumn (w przypadku StringGrid zastąpi wartość określoną w odpowiedniej właściwości Cells[ColumnIndex, RowTitle]), wyrównanie tekstu, kolor tła, preferowany edytor itp.

Kolumny niestandardowe dodają dodatkowe właściwości lub zastępują domyślne wartości właściwości w normalnych kolumnach siatki. Ponadto, wartość grid.ColCount może się zwiększyć lub zmniejszyć w celu uwzględnienia liczby niestandardowych kolumn dołączanych do siatki. A to oznacza, że grid.ColCount = grid.FixedCols + grid.Columns.Count.

Na przykład, jeśli mamy siatkę bazową z ColCount := 5 i FixedCols := 2 i wykonamy:

  • Dodaj 3 niestandardowe kolumny, to siatka bazowa będzie dokładnie taka sama, jak poprzednio, 2 stałe kolumny i 3 normalne kolumny.
  • Dodaj 1 niestandardową kolumnę, to siatka bazowa będzie miała ColCount := 3, czyli 2 stałe kolumny i 1 normalną kolumnę.
  • Dodaj 4 niestandardowe kolumny, to siatka bazowa będzie miała ColCount := 6, czyli 2 stałe kolumny i 4 normalne kolumny.

Z tego możemy wywnioskować, że:

  • Stałe właściwości lub liczba kolumn nie są odpowiednio ulepszane ani modyfikowane przez kolumny niestandardowe.
  • grid.ColCount zwykle różni się od grid.Columns.Count ('grid.ColCount=grid.Columns.Count tylko wtedy, gdy ' FixedCols=0)

W czasie projektowania w Inspektorze obiektów użytkownik może uzyskać dostęp do właściwości columns, aby wywołać edytor kolumn. Stamtąd można dodawać, usuwać lub modyfikować niestandardowe kolumny. Edytor wyświetla listę aktualnych kolumn niestandardowych; wybierając elementy z tej listy, inspektor obiektów zostaje wypełniony właściwościami dostępnymi dla każdej kolumny. Lista niestandardowych kolumn jest również dostępna w widoku drzewa komponentów Inspektora obiektów, gdzie kolumny można dodawać, usuwać lub modyfikować. Pojawiają się na niższym poziomie pod siatką kontenerów.

W czasie wykonywania programu, kolumny można modyfikować za pomocą kodu w następujący sposób:

  var
    c: TGridColumn;
  begin
    // dodaj niestandardową kolumnę siatki
    c := Grid.Columns.Add;
    // modyfikuj kolumnę
    c.title.caption := 'Price';       // Ustaw tytuły kolumn
    c.align := taRightJustify;        // Wyrównaj zawartość kolumny do prawej
    c.color := clMoneyGreen;          // Zmień domyślny kolor na clMoneyGreen
    c.Index := 0;                     // Niech to będzie pierwsza kolumna
    // uzyskać dostęp do istniejącej kolumny
    grid.columns[0].Width := 60;      // Zmień szerokość kolumny 0 na 60 pikseli
    // usuń istniejącą kolumnę
    grid.columns.delete(0);           // Usuń kolumnę 0
    ....
  end;

Dodatkowo, podczas korzystania z niestandardowych kolumn, siatki nie pozwalają na bezpośrednią modyfikację grids.colcount; dodawanie lub usuwanie kolumn powinno odbywać się za pomocą właściwości columns. Wyjaśnienie jest takie, że istnieje niespójność w stopniowym usuwaniu niestandardowych kolumn za pomocą ColCount, gdy ColCount osiągnie FixedCols, siatka nie ma więcej niestandardowych kolumn. Jeśli teraz zwiększymy ColCount, nowa kolumna nie będzie kolumną niestandardową, ale normalną.

Obecnie nie ma planów, aby siatki wykorzystywały tylko kolumny niestandardowe.

Właściwość AutoFillColumns

Często siatki są szersze niż pozioma przestrzeń potrzebna kolumnom - pozostawia to nieprzyjemny pusty obszar po prawej stronie ostatniej kolumny. Siatki LCL zapewniają mechanizm rozszerzania szerokości określonych kolumn w taki sposób, że puste miejsce jest wypełniane automatycznie.

W tym celu należy dodać Columns zgodnie z opisem powyżej lub przez ustawienie właściwości ColCount oraz właściwości siatki AutoFillColumns, która musi być ustawiona na True. Każda kolumna ma właściwość SizePriority. Gdy ma wartość 0, szerokość kolumny jest pobierana z właściwości Width kolumny. Ale gdy ma wartość niezerową, szerokość kolumny jest dostosowywana do średniego dostępnego rozmiaru pozostałego dla wszystkich kolumn z niezerowym SizePriority.

Procedura SaveToFile(AFileName: String)

Zapisuje siatkę do pliku XML. Właściwość SaveOptions określa, co dokładnie ma zostać zapisane:

type
  TGridSaveOptions = (
    soDesign,             // Zapisz strukturę siatki (liczba kolumn/wierszy i opcje - Options)
    soAttributes,         // Zapisz atrybuty siatki (czcionka - Font, pędzel - Brush, styl tekstu TextStyle)
    soContent,            // Zapisz zawartość siatki (tekst w StringGrid)
    soPosition            // Zapisz kursor siatki i pozycję zaznaczenia
  );
  TSaveOptions = set of TGridSaveOptions;

Procedura LoadFromFile(AFileName: String)

Ładuje plik XML utworzony przez SaveToFile. Ponownie, SaveOptions określają, co dokładnie ma zostać załadowane z pliku.

TCustomDBGrid

TCustomDBGrid jest podstawą dla TDBGrid.

Nie ujawniają właściwości Col i Row. Aby przejść do określonej kolumny, użyj np. właściwość SelectedIndex.

Ciekawą metodą publiczną jest AutoAdjustColumns.

Procedura AutoAdjustColumns

Ta procedura ustawia szerokość kolumny na rozmiar najszerszego znalezionego tekstu. Można go używać po załadowaniu zestawu danych/ustawieniu go jako Aktywny - Active.

Jednak w przeciwieństwie do TCustomStringGrid.AutoAdjustColumns (patrz poniżej), spowoduje to ustawienie bardzo szerokich kolumn, chyba że masz włączoną właściwość dgAutoSizeColumns.

Procedura InplaceEditor

Zobacz przykład z błędu 23103 - i wstaw wyjaśnienie, co robi/dlaczego jest to potrzebne. Weryfikuje wartości wejściowe? Zmienia to, co jest wyświetlane?

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: char);
var
  S: String;
begin
  if (Key in [',','.']) then
  begin
    //w przeciwieństwie do Delphi nie wszystkie edytory InPlaceEditors są edytorami typu string, więc sprawdź!
    if (DBGrid1.InplaceEditor is TStringCellEditor) then
    begin
      S := TStringCellEditor(DBGrid1.InplaceEditor).EditText;
      if Pos(',',S) > 0 then
        Key := #0
      else
        Key := ',';
    end;
  end;
end;

TCustomStringGrid

Klasa TCustomStringGrid służy jako podstawa dla klasy TStringGrid. Może być używana dla pochodnych komponentów TStringGrid, które chcą ukryć opublikowane właściwości.

Następujące właściwości lub metody są publiczne i są również dostępne dla TStringGrid.

Zobacz pełną dokumentację TCustomStringGrid

Procedura AutoSizeColumn(aCol: Integer)

Ta procedura dostosowuje szerokość kolumny do rozmiaru najszerszego tekstu, jaki znajduje się pośród wszystkich wierszy kolumny aCol. Wskazówka: zobacz opcję goDblClickAutoSize, która umożliwia automatyczną zmianę szerokości kolumny, gdy użyjemy podwójnego kliknięcia na obramowaniu tejże kolumny.

Procedura AutoAdjustColumns lub AutoSizeColumns

Automatycznie zmienia szerokość wszystkich kolumn, dopasowując je do najdłuższego tekstu w każdej kolumnie. Jest to szybka metoda zastosowania funkcji AutoSizeColumn() dla każdej kolumny w siatce.

Procedura Clean; overload;

Czyści wszystkie komórki siatki, także te stałe (typu fixed).

Procedura Clean(CleanOptions: TGridZoneSet); overload;

Czyści wszystkie komórki w siatce wskazane w parametrze CleanOptions. Zobacz TGridZoneSet aby uzyskać więcej informacji. Poniżej kilka przykładów:

  • Czyści wszystkie komórki: grid.Clean([]); (działa tak samo jak grid.clean)
  • Czyści wszystkie normalne (nie stałe - non fixed) komórki: grid.Clean([gzNormal]);
  • Czyści wszystkie komórki oprócz nagłówków kolumn siatki: Grid.Clean([gzNormal, gzFixedRows]);

Procedura Clean(StartCol,StartRow,EndCol,EndRow: integer; CleanOptions:TGridZoneSet); overload;

Wykonuje to samo co Clean(CleanOptions:TGridZoneSet), ale jej działanie ograniczone jest obszarem określonym parametrami StartCol, StartRow, EndCol i EndRow. Przykład:

  • Czyści kolumny o ideksach od 4 do 6, ale bez nagłówków kolumn: można to zrobić na wiele sposobów, Grid.Clean(4,Grid.FixedRows,6,Grid.RowCount-1,[]); Grid.Clean(4,0,6,Grid,RowCount-1, [gzNormal]); itp.

Procedura Clean(aRect: TRect; CleanOptions: TGridZoneSet); overload;

Wykonuje to samo co Clean(StartCol,StartRow,EndCol,EndRow, CleanOptions), ale przy pomocy TRect zamiast wskazywania pojedynczych współrzędnych komórek. Przydatne do czyszczenia zaznaczonego obszaru: grid.Clean(Grid.Selection,[]);

Procedura SaveToCSVFile(AFileName: string; ADelimiter:Char=','; WithHeader:boolean=true);

Zapisuje zawartość siatki w pliku w formacie tekstowym, gdzie wartości są rozdzielone przecinkami (CSV) (dodanym w Lazarus r32179).

Argument AFilename określa nazwę pliku, w którym zostanie zapisana zawartość. Jeśli plik istnieje, zawartość zostanie nadpisana. Jeśli nie istnieje, plik zostanie utworzony.

ADelimiter (argument opcjonalny) jest używany do dostarczenia niestandardowego separatora, jeśli jest to wymagane. Domyślnie tworzony jest format CSV (tzn. ADelimiter:=',';) dla pliku rozdzielanego tabulatorami ADelimiter powinien mieć wartość #9.

Parametr WithHeader służy do określenia, czy „nagłówek wiersza” powinien zostać uwzględniony, czy nie. Nagłówek wiersza to lista nazw pól na początku pliku wyjściowego; jego zawartość pochodzi z ostatniego stałego (Fixed) wiersza w siatce. Istnieje wyjątek od tej reguły: jeśli siatka zawiera niestandardowe kolumny, zawartość nagłówka wiersza pochodzi z niestandardowych tytułów kolumn, a nie ze stałych komórek wiersza.

Jeśli WithHeader ma wartość True, a siatka nie zawiera stałego wiersza ani niestandardowych kolumn, zawartość nagłówka wiersza zostanie pobrana z pierwszego wiersza w siatce.

Normalne wyjście danych CSV rozpocznie się od pierwszego niestałego (Non-Fixed) wiersza w siatce.

Procedura LoadFromCSVFile(AFileName: string; ADelimiter:Char=','; WithHeader:boolean=true);

Wczytuje zawartość siatki z pliku w formacie CSV (dodanym w Lazarus r32179).

Kolumny będą dodawane lub usuwane do lub z siatki w zależności od potrzeb, zgodnie z liczbą pól zawartych w każdym wierszu pliku CSV. Wczytanie pliku CSV nie zmieni liczby stałych (Fixed) wierszy, które już istniały w siatce.

Argument AFileName określa nazwę pliku źródłowego z zawartością CSV.

Opcjonalny parametr ADelimiter może być użyty do określenia innego separatora lub ogranicznika. Przykład: dla pliku rozdzielanego tabulatorami, ADelimiter powinno mieć wartość #9. Innym popularnym formatem pliku jest plik rozdzielany średnikami, gdzie ADelimiter powinien być ;

Parametr WithHeader służy do określenia, czy pierwszy wiersz w pliku CSV powinien być traktowany jako „wiersz nagłówka”, czy nie. Jeśli siatka ma ustalone wiersze i WithHeader ma wartość True, nagłówki kolumn dla ostatniego stałego (Fixed) wiersza zostaną pobrane z wiersza nagłówka. Należy jednak pamiętać, że jeśli siatka zawiera niestandardowe kolumny, wówczas wiersz nagłówka będzie używany jako źródło dla tytułów kolumn, a niestandardowe tytuły kolumn są zawsze wyświetlane w pierwszym stałym wierszu siatki lub ukryte, jeśli w siatce nie ma ustalonych wierszy.

Jeśli procedura LoadFromCSVFile ma trudności z załadowaniem pliku CSV (np. cudzysłowy lub spacje są nieprawidłowo interpretowane), możesz ręcznie załadować siatkę za pomocą np. CsvDocument... i oczywiście zawsze mile widziana jest łatka dla LoadFromCSVFile.

Właściwość Cols[index: Integer]: TStrings read GetCols write SetCols;

Pobierz/wstaw listę ciągów string z/do kolumny siatki o wskazanym indeksie, począwszy od wiersza o indeksie 0 do wiersza o indeksie RowCount-1.

Przykłady
  • Przykład wstawiania: Wstawia treść do trzeciej kolumny siatki z kontrolki ListBox:
Grid.Cols[2] := ListBox1.Items;
  • Przykład pobrania: Wstawia treść kontrolki ListBox z kolumny siatki o indeksie 4:
procedure TForm1.FillListBox1;
var 
  StrTempList: TStringList;
begin
  StrTempList := TStringList(Grid.Cols[4]);
  if StrTempList<>nil then begin
    ListBox1.Items.Assign(StrTempList);
    StrTempList.Free;
  end;
end;
Uwagi

Ta właściwość działa inaczej w Lazarusie i w Delphi, gdy pobieramy dane z siatki. W Lazarusie tworzony jest tymczasowy obiekt typu TStringList w celu pobrania zawartości kolumny. Użytkownik jest odpowiedzialny za zwolnienie tego obiektu po użyciu.

Oznacza to także, że zmiany wykonywane w tej zwróconej liście ciągów string nie będą miały żadnego wpływu na zawartość siatki lub układu.

Zobacz powyższy przykład pobrania.

Właściwość Rows[index: Integer]: TStrings read GetRows write SetRows;

Pobierz/ustaw listę ciągów string z/do wiersza siatki o danym indeksie, począwszy od indeksu kolumny 0 do kolumny ColCount-1.

Uwagi

Ta właściwość działa inaczej w Lazarusie i Delphi podczas pobierania danych z siatki. W Lazarusie tworzony jest tymczasowy obiekt typu TStringList do pobierania zawartości wiersza. Obowiązkiem użytkownika jest zwolnienie tego obiektu po użyciu.

Oznacza to również, że jakiekolwiek zmiany w tej zwróconej liście ciągów string nie wpłyną na zawartość ani układu, ani siatki.

Przykłady
  • Przykład ustawiania: Ustaw zawartość trzeciego wiersza siatki jako zawartość ListBox:
Grid.Rows[2] := ListBox1.Items;
  • Przykład pobrania: Ustaw zawartość pola listy z 4 indeksu wiersza siatki:
procedure TForm1.FillListBox1;
var 
  StrTempList: TStringList;
begin
  StrTempList := TStringList(Grid.Rows[4]);
  if StrTempList<>nil then begin
    ListBox1.Items.Assign(StrTempList);
    StrTempList.Free;
  end;
end;
  • Przykład, który nie działa, oraz jego poprawka: Pobrana lista ciągów jest tylko do odczytu
 // te dwa przykłady nie zadziałają i spowodują wycieki pamięci,
 // ponieważ zwrócone listy ciągów nie są zwalniane
 Grid.Rows[1].CommaText := '1,2,3,4,5';
 Grid.Rows[2].Text := 'a'+#13#10+'s'+#13#10+'d'+#13#10+'f'+#13#10+'g'; 
 
 // naprawienie pierwszego przypadku
 Lst:=TStringList.Create;
 Lst.CommaText := '1,2,3,4,5';
 Grid.Rows[1] := Lst;
 Lst.Free;

Właściwość UseXORFeatures

Właściwość typu Boolean, wartość domyślna: False;

Ta właściwość kontroluje wygląd kropkowanego prostokąta fokusu w siatce (pokazuje się, gdy klikniemy myszką na jakiejś komórce). Gdy ma wartość True, prostokąt jest malowany przy użyciu operacji rastrowej XOR. Dzięki temu możemy zobaczyć prostokąt fokusu bez względu na kolor tła komórek. Gdy ma wartość False, użytkownik może kontrolować kolor kropkowanego prostokąta fokusu za pomocą właściwości FocusColor

Kontroluje również wygląd zmiany rozmiaru kolumny/wiersza. Gdy ma wartość True, linia pokazuje wizualnie rozmiar kolumny lub wiersza, jeśli użytkownik zakończy operację. Gdy ma wartość False, zmiana rozmiaru kolumny lub wiersza zaczyna obowiązywać, gdy użytkownik przeciąga myszą.

TValueListEditor

TValueListEditor to kontrolka (formant) pochodzący z TCustomStringGrid i służy do edycji par typu klucz-wartość.

Właściwość DisplayOptions

Kontroluje różne aspekty wyglądu TValueListEditor.

Właściwość TitleCaptions

Ustawia wartości dla tytułów kolumn (jeśli właściwość DisplayOptions zawiera wartość doColumnTitles). Jeśli DisplayOptions nie ma wartości doColumnTitles, używane są domyślne tytuły.

Właściwość Strings

Zapewnia dostęp do listy ciągów zawierających pary klucz-wartość.
Pary klucz-wartość muszą mieć format typu:
'NazwaKlucza=Wartość'

Właściwość ItemProps

Możesz użyć tej właściwości, aby kontrolować sposób edytowania elementów w kolumnach „Value” (Wartość).
Jest to kontrolowane przez ustawienie właściwości EditStyle i ReadOnly elementu ItemProp.

Właściwość KeyOptions

KeyOptions to zbiór wartości porządkowych TKeyOptions kontrolujących, czy użytkownik może modyfikować zawartość kolumny „Key” (Klucz).

  • KeyEdit: użytkownik może edytować nazwę klucza
  • KeyAdd: użytkownik może dodawać klucze (przez wciśnięcie klawisza Insert w siatce). KeyAdd wymaga KeyEdit.
  • KeyDelete: użytkownik może usuwać pary klucz-wartość (przez naciśnięcie kombinacji Ctrl+Delete).
  • KeyUnique: jeśli ustawione, klucze muszą mieć unikalne nazwy. Próba wprowadzenia zduplikowanego klucza spowoduje zgłoszenie wyjątku.

Właściwość DropDownRows

Jeśli edytor komórek jest listą wyboru (ValueEdit1.ItemProps['key1'].EditStyle=esPickList), to ta właściwość ustawia DropDownCount, czyli ilość wierszy wyświetlanej listy. Wartość domyślna to 8.

Funkcja DeleteRow

Usuwa parę Klucz-Wartość wiersza o podanym indeksie, całkowicie usuwając wiersz.

Funkcja InsertRow

Wstawia wiersz w siatce i ustawia parę Klucz-Wartość. Zwraca indeks nowo wstawionego wiersza.

Funkcja IsEmptyRow

Zwraca wartość True, jeśli komórki indeksowanego wiersza są puste (Keys[aRow]=; Values[aRow]=).

Funkcja FindRow

Zwraca indeks wiersza, który ma określoną nazwę klucza.

Funkcja RestoreCurrentRow

Cofa edycję w bieżącym wierszu (jeśli edytor jest nadal aktywny). Dzieje się tak, gdy użytkownik naciśnie klawisz Escape.

Zmienione zachowanie niektórych właściwości pochodzących z TCustomStringGrid

Właściwość Options

Ze względu na charakter TValueListEditor jego właściwość Options ma pewne ograniczenia

  • goColMoving nie jest dozwolony w opcjach (nie można go ustawić).
  • goAutoAddRows można ustawić tylko wtedy, gdy KeyAdd jest włączony w KeyOptions. Ustawienie KeyAdd automatycznie ustawi goAutoAddRows.
  • goAutoAddRowsSkipContentCheck jest niedozwolone (na razie powoduje awarię w TValueListeditor: wymaga naprawy).
Właściwość FixedRows

Może mieć wyłącznie wartość równą 1 (pokaż tytuły kolumn) lub 0 (nie pokazuj tytułów kolumn).

Właściwość ColCount

Może mieć wyłącznie wartość równą 2.

Właściwość Objects

Uwaga! Nie zaleca się używania tej właściwości w ogóle.
Kiedy jakiś (wewnętrzny) kod manipuluje właściwością Strings, zmiany dla Objects zostaną utracone.

Ogólne uwagi dotyczące korzystania z TValueListEditor

Podczas manipulowania zawartością ValueListEditor (siatki) można bezpośrednio manipulować podstawową właściwością Strings.
Pamiętaj jednak, że jeśli to zrobisz, musisz ukryć edytor, w przeciwnym razie ciągi mogą nie być zsynchronizowane z zawartością siatki, którą widzisz na ekranie.

Jeśli chcesz wstawić lub usunąć wiersze itp., preferowanym sposobem jest użycie metod publicznych z TValueListEditor: DeleteRow(), InsertRow(), MoveRow(), ExchangeRow() lub różnych metod Sort().

Próba użycia metod z klasy przodka do manipulowania wierszami lub kolumnami (np. Columns.Add) może spowodować awarię.

Zapisywanie i ładowanie zawartości TValueListEditor

Korzystanie z właściwości Strings

Jeśli chcesz tylko zapisać i załadować zawartość TValueListEditor (np. par Klucz/Wartość, a nie układ), możesz użyć metod Strings.SaveToFile i Strings.LoadFromFile.
W przypadku LoadFromFile właściwość RowCount zostanie automatycznie dostosowana.
Również w przypadku LoadFromFile nie są wykonywane żadne kontrole poprawności (więc wiersze, które nie reprezentują pary Klucz/Wartość, zostaną zakończone jako klucze bez wartości).

Korzystanie z TValueList.SaveToFile i TValueList.LoadFromFile

When using SaveToFile and LoadFromFile you get the additional benefits of also being able to save and load the layout, like with other grids.
SaveToFiel will also save information about wether or not the TValueListEditor uses ColumnTitles, and if so, it saves them.

In contrast to it's ancestors TValueList.LoadFromFile performs sanity checks on the file it tries to read. In particular RowCount must be specified and there cannot be a cell with RowIndex > RowCount or ColumnIndex other than 0 or 1.
If the file does not seem to be a valid TValueListEditor grid file, and exception is raised.

TValueList.SaveToFile and TValueList.LoadFromFile do not work correctly in Lazarus versions <= 2.1 r62044.

Korzystając z funkcji SaveToFile i LoadFromFile z TValueList, zyskujesz dodatkowe korzyści związane z możliwością zapisywania i ładowania układu, podobnie jak w przypadku innych siatek.
SaveToFile zapisze również informacje o tym, czy TValueListEditor używa ColumnTitles, a jeśli tak, zapisuje je.

W przeciwieństwie do swoich przodków, TValueList.LoadFromFile sprawdza poprawność pliku, który próbuje odczytać. W szczególności właściwość RowCount musi być określona i nie może istnieć komórka z RowIndex > RowCount lub ColumnIndex innym niż 0 lub 1.
Jeśli plik nie wydaje się być prawidłowym plikiem siatki TValueListEditor, zgłaszany jest wyjątek.

TValueList.SaveToFile i TValueList.LoadFromFile nie działają poprawnie w wersjach Lazarusa <= 2.1 r62044.

Korzystanie z metod SaveToCSVFile i LoadFromCSV

Te metody nie powinny być obecnie używane, ponieważ w przypadku TValueListEditor są one wadliwe.

Praca z siatkami

Dostosowywanie siatek

Komponenty Grid pochodzą z klasy TCustomControl i nie mają skojarzonego z nią natywnego widżetu, co oznacza, że ​​siatki nie są ograniczone przez wygląd aktualnego motywu interfejsu. Może to być zarówno zaletą, jak i wadą: zwykle programiści chcą stworzyć aplikację o jednolitym wyglądzie. Dobrą wiadomością jest to, że siatki Lazarusa są wystarczająco elastyczne, aby uzyskać coś z obu światów; programiści mogą łatwo sprawić, by siatki wyglądały podobnie do innych natywnych kontrolek, lub mogą dostosować siatkę w najdrobniejszych szczegółach, aby uzyskać prawie taki sam wygląd na dowolnej platformie lub interfejsie widżetów (tzn. z wyjątkiem pasków przewijania, ponieważ ich wygląd jest wciąż zdeterminowany aktualnym motywem).

Właściwości i Zdarzenia dostosowujące siatek

Niektóre właściwości mogą wpływać na wygląd siatki, działając, gdy komórka ma zostać pomalowana w zdarzeniu PrepareCanvas/OnPrepareCanvas, zmieniając domyślne właściwości płótna (canvas), takie jak kolor pędzla lub czcionka. Poniżej znajduje się lista takich właściwości:

  • AlternateColor. Dzięki tej właściwości użytkownik może zmienić kolor tła pojawiający się w naprzemiennych wierszach. Ma to na celu umożliwienie łatwiejszego odczytania danych z wierszy siatki przez użytkownika.
  • Color. Ta właściwość ustawia podstawowy kolor używany do rysowania tła niestałych (Non-Fixed) komórek.
  • FixedColor. Jest to kolor używany do rysowania tła dla stałych komórek (Fixed).
  • Flat. Ta właściwość wyłącza trójwymiarowy wygląd stałych komórek.
  • TitleFont. Czcionka używana do rysowania tekstu w stałych komórkach.
  • TitleStyle. Ta właściwość zmienia wygląd 3D stałych komórek, istnieją 3 ustawienia:
    • tsLazarus. To jest domyślny wygląd preferowany przez Lazarusa
    • tsNative. Ta wartość próbuje ustawić wygląd zgodny z bieżącym motywem zestawu widżetów.
    • tsStandard. Ten styl jest bardziej kontrastowy, podobnie jak siatki Delphi.
  • AltColorStartNormal. Wartość logiczna. Jeśli jest True: alternatywny kolor jest zawsze w drugim rzędzie po stałych wierszach, pierwszy wiersz po stałych wierszach będzie zawsze w domyślnym kolorze. Jeśli jest False: domyślny kolor jest ustawiany na pierwszym wierszu, tak jakby nie było żadnych stałych wierszy.
  • BorderColor. Ustawia kolor obramowania siatki używany, gdy Flat:=True i BorderStyle:=bsSingle.
  • EditorBorderStyle. Jeśli ustawione na bsNone w systemie Windows, to edytory komórek nie będą miały obramowania, tak jak w Delphi. Ustaw domyślnie na bsSingle, ponieważ obramowanie może być specyficzne dla motywu w niektórych zestawach widżetów i umożliwiać jednolity wygląd.
  • FocusColor. Kolor używany do rysowania komórki, na której aktualnie ustawione jest skupienie (fokus), jeśli UseXORFeatures nie jest ustawiony, domyślnie jest to clRed.
  • FocusRectVisible. Włącza/wyłącza rysowanie skupionej komórki.
  • GridLineColor. Kolor linii siatki w obszarze niestałych komórek.
  • GridLineStyle. Styl pióra używany do rysowania linii w obszarze niestałych komórek, możliwe wybory to: psSolid, psDash, psDot, psDashDot, psDashDotDot, psinsideFrame , psPattern, psClear. Domyślnie jest to psSolid.
  • SelectedColor. Kolor używany do rysowania tła komórki na wybranych, zaznaczonych komórkach.
  • UseXORFeatures. Jeśli ustawiony jest na True, to prostokąt skupienia (focus) jest rysowany w trybie XOR, więc powinien być widoczny w połączeniu z dowolnym kolorem tła komórki. Wpływa również na wygląd przesuwanych kolumn.
  • DefaultDrawing. Wartość logiczna. Zwykle siatki przygotowują płótno (canvas) siatki przy użyciu pewnych właściwości zgodnie z rodzajem malowanej komórki. Jeśli użytkownik napisze własną procedurę obsługi zdarzeń OnDrawCell, ustawiony DefaultDrawing również maluje tło komórki. Jeśli użytkownik sam rysuje komórkę, lepiej wyłączyć tę właściwość, aby malowanie się nie duplikowało. W StringGrid ustawiony DefaultDrawing rysuje również tekst w każdej komórce.
  • AutoAdvance. Determinuje to, gdzie ma zostać przeniesiony kursor komórki po naciśnięciu klawisza Enter lub po zakończeniu edycji.
  • TabAdvance. Determinuje to, gdzie ma zostać przeniesiony kursor komórki po naciśnięciu klawisza Tab or Shift-Tab.
  • ExtendedColSizing. Jeśli ma wartość True, użytkownik może zmienić rozmiar kolumn nie tylko w nagłówkach, ale wzdłuż ich wysokości.

Inne właściwości, które również wpływają na wygląd siatek.

Options.

Właściwość Options to zestaw zawierający kilka elementów umożliwiających różnorodną funkcjonalność, ale niektóre są bezpośrednio związane z wyglądem siatki. Te opcje można ustawić w czasie projektowania lub w czasie wykonywania.
  • goFixedVertLine, goFixedHorzLine Rysuje pionową lub poziomą linię, odpowiednio oddzielającą komórki lub kolumny w obszarze stałych komórek, domyślnie aktywne.
  • goVertLine, goHorzLine Tak samo jak poprzednio, ale dla normalnego obszaru do przeglądania. Można stworzyć siatkę, która będzie symulować pole listy (ListBox), wyłączając oba te elementy.
  • goDrawFocusSelected Jeśli ten element jest włączony, tło zaznaczenia jest malowane także w skupionej (fixed) komórce oprócz zaznaczonego kropkowanego prostokąta (pamiętaj, że to nie działa jeszcze, gdy ustawiona jest opcja goRowSelect, w takim przypadku wiersz jest zawsze malowany tak, jakby ustawiono goDrawFocusSelected).
  • goRowSelect Wybierz do zaznaczania cały wiersz zamiast pojedynczych komórek.
  • goFixedRowNumbering Jeśli ustawione, siatka wykona automatyczną numerację wierszy w pierwszej stałej kolumnie.
  • goHeaderHotTracking Jeśli jest ustawione, siatka będzie próbowała pokazać inny wygląd komórki, gdy kursor myszy znajdzie się nad dowolną stałą komórką. Aby to zadziałało, żądana strefa komórki musi być włączona za pomocą właściwości HeaderHotZones. Spróbuj połączyć tę opcję z właściwością TitleStyle:=tsNative, aby uzyskać wygląd, który na bieżąco śledzi wygląd motywu widżetów.
  • goHeaderPushedLook Jeśli jest ustawione, ten element włącza wygląd wciśnięcia po kliknięciu dowolnej stałej komórki. Strefa komórek, które mogą być „wciskane” jest włączana za pomocą właściwości HeaderPusedZones.

(dopisz więcej)

Opis procesu rysowania siatki

Podobnie jak inne niestandardowe kontrolki, siatka jest rysowana metodą malowania. Ogólnie rzecz biorąc, siatkę rysuje się malując wszystkie wiersze, a każdy wiersz malując poszczególne komórki.

Proces ten wygląda następująco:

  • Najpierw określany jest obszar widocznych komórek: każdy wiersz jest testowany, aby sprawdzić, czy krzyżuje się z granicą płótna (canvas); jeśli wszystko jest w porządku, widoczny obszar jest malowany przez rysowanie kolumn każdego wiersza.
  • Wartości kolumn i wierszy służą do identyfikacji komórki, która ma zostać pomalowana, a każda kolumna jest ponownie testowana pod kątem krzyżowania się z granicą płótna; jeśli wszystko jest w porządku, niektóre dodatkowe właściwości, takie jak prostokątny zasięg komórki i stan wizualny, są przekazywane jako argumenty do metody DrawCell.
  • W trakcie procesu rysowania stan wizualny każdej komórki jest dostosowywany zgodnie z opcjami siatki i położeniem w siatce. Stan wizualny zachowany jest w zmiennej typu TGridDrawState, która jest zbiorem składającym się z następujących elementów:
    • gdSelected Komórka będzie miała wygląd wybranej, zaznaczonej.
    • gdFocused Komórka będzie miała wygląd skupionej (focus).
    • gdFixed Komórka musi być pomalowana jak komórka stała.
    • gdHot Mysz jest nad tą komórką, więc pomaluj ją z bieżącym podświetleniem
    • gdPushed Komórka jest klikana, więc pomaluj ją jako wciśniętą
  • DrawCell. Metoda DrawCell jest wirtualna i może zostać zastąpiona w siatkach potomnych w celu wykonania niestandardowego rysowania. Informacje przekazywane do DrawCell pomagają zidentyfikować konkretną komórkę, która jest malowana, fizyczny obszar zajmowany na ekranie i widoczny status. Zobacz odwołanie do DrawCell, aby uzyskać szczegółowe informacje. Dla każdej komórki wykonywane są następujące operacje:
  • PrepareCanvas. W tej metodzie, jeśli ustawiona jest właściwość DefaultDrawing, płótno siatki jest skonfigurowane z domyślnymi właściwościami pędzla i czcionki na podstawie bieżącego stanu wizualnego. W przypadku kilku właściwości wyglądu i środowiska wykonawczego wyrównanie tekstu jest ustawiane tak, aby było zgodne z wyborem programisty w niestandardowych kolumnach, jeśli takie istnieją. Jeśli DefaultDrawing ma wartość False, kolor pędzla jest ustawiony na clWindow, a kolor czcionki na clWindowText, wyrównanie tekstu jest ustawiane za pomocą wartości właściwości siatek defaultTextStyle.
  • OnPrepareCanvas. Jeśli programista napisał obsługę zdarzenia dla zdarzenia OnPrepareCanvas, jest on wywoływany w tym momencie. To zdarzenie może służyć do wykonywania prostych dostosowań, takich jak zmiana koloru tła komórki, właściwości czcionki, takie jak kolor, czcionka i styl, układ tekstu, na przykład różne kombinacje wyrównania do lewej, do środka, do góry, do dołu, do prawej itp. Wszelkie zmiany wprowadzone na płótnie w tym zdarzeniu zostałoby utracone, ponieważ następujące potem rysowanie komórki ponownie zresetuje obszar roboczy do stanu domyślnego. Więc bezpieczniej jest robić zmiany tylko dla konkretnej komórki lub komórek i zapomnieć o pozostałych. Użycie tego zdarzenia czasami pomaga uniknąć użycia zdarzenia siatki OnDrawCell, w którym użytkownicy byliby zmuszeni do powielenia kodu rysowania siatki. Do zrobienia: informacje o tym, co można zrobić tutaj, a co zostawić dla zdarzenia OnDrawCell?...
  • OnDrawCell. Następnie, jeśli nie określono obsługi zdarzenia OnDrawCell, siatka wywołuje metodę DefaultDrawCell, która po prostu maluje tło komórki przy użyciu bieżącego koloru i stylu pędzla płótna. Jeśli istnieje procedura obsługi OnDrawCell, siatka najpierw maluje tło komórki, ale tylko wtedy, gdy ustawiono właściwość DefaultDrawing, a następnie wywołuje zdarzenie OnDrawCell w celu wykonania niestandardowego malowania komórek. Zwykle programiści chcą wykonywać niestandardowe rysowanie tylko dla określonych komórek, ale standardowe rysowanie dla innych; w tym przypadku mogą ograniczyć niestandardową operację do określonej komórki lub komórek, zaglądając do argumentów ACol, Arow i AState, a dla innych komórek po prostu wywołując metodę DefaultDrawCell, aby pozwolić zająć się tym siatce.
  • Text. W tym momencie (tylko dla TStringGrid), jeśli właściwość DefaultDrawing ma wartość True, malowana jest zawartość tekstowa komórki.
  • Grid lines. Ostatnim krokiem dla każdej komórki jest malowanie linii siatki: jeśli określono opcje siatki goVertLine, goHorzLine, goFixedVertLine i goFixedHorzLine, siatka komórek jest rysowana w tym miejscu. Siatki zawierające tylko wiersze lub tylko kolumny można uzyskać, zmieniając te opcje. Jeśli programista wybrał wygląd „motywu” (tsNative), jest to również robione w tym momencie (zobacz właściwość TitleStyle).
  • FocusRect. Po pomalowaniu wszystkich kolumn bieżącego wiersza nadszedł czas na narysowanie prostokąta skupienia (focus) dla aktualnie zaznaczonej komórki lub dla całego wiersza, jeśli ustawiono opcję goRowSelect.

Różnice w porównaniu z Delphi

  • W Lazarusie metoda TCustomGrid.DrawCell nie jest abstrakcyjna i jej domyślna implementacja wykonuje podstawowe wypełnianie tła komórki.
  • W Delphi tekst komórki jest rysowany przed wejściem do zdarzenia OnDrawCell (patrz raport o błędzie #9619).

Wybór komórki w siatce

Lokalizację bieżącej (skupionej (focused)) komórki (lub wiersza) siatki można zmienić za pomocą klawiatury, myszy lub kodu. Aby skutecznie zmienić skupienie z jednej komórki na inną, musimy przetestować pozycję docelową, aby sprawdzić, czy może ona otrzymać skupienie na komórce. W przypadku korzystania z klawiatury właściwość część procesu wykonuje AutoAdvance, znajdując następną komórkę, na której ma wykonać skupienie. Podczas korzystania z kliknięć myszą lub poruszania się po kodzie, skupienie nie zostanie przeniesione z bieżącej komórki, chyba że komórka docelowa może takie skupienie otrzymać.

Siatka wywołuje funkcję SelectCell, aby sprawdzić, czy na komórce można wykonać skupienie: jeśli ta funkcja zwraca wartość True, to znaczy, że na komórce docelowej, zidentyfikowanej za pomocą argumentów aCol i aRow jest możliwe wykonanie skupienia (bieżąca implementacja TCustomGrid po prostu zwraca True). TCustomDrawGrid, a zatem także TDrawGrid i TStringGrid przesłaniają tę metodę, aby najpierw sprawdzić, czy komórka jest szersza niż 0; normalnie nie chcesz, aby wybrana została komórka o szerokości 0, więc komórka z tymi cechami jest automatycznie pomijana w procesie wyszukiwania odpowiedniej komórki. Inną rzeczą, jaką robi zastąpiona metoda SelectCell, jest wywołanie konfigurowanego przez użytkownika zdarzenia OnSelectCell: to zdarzenie odbiera współrzędne komórki jako argumenty i zawsze zwraca w wyniku domyślną wartość True.

Gdy wiadomo, że komórka może uzyskać skupienie i jesteśmy pewni, że nastąpi ruch, najpierw wywoływana jest metoda BeforeMoveSelection; to z kolei wyzwala zdarzenie OnBeforeSelection. Argumentami tej metody są współrzędne nowej komórki ze skupieniem. W tym momencie każdy widoczny edytor jest również ukryty. Słowo „before” (przed) oznacza, że ​​zaznaczenie nie zostało jeszcze zmienione, a dostęp do aktualnych współrzędnych komórki skupionej można uzyskać za pomocą właściwości grid.Col i grid.Row.

Następnie wewnętrzne współrzędne skupionej komórki są zmieniane, a potem wywoływana jest metoda MoveSelection; celem tej metody jest wyzwolenie zdarzenia OnSelection, jeśli jest ustawione (jest to powiadomienie, że skupiona komórka już się zmieniła, a współrzędne komórki są teraz dostępne we właściwościach grid.row i grid.col).

Należy zauważyć, że nie jest dobrze używać zdarzenia OnSelectCell do wykrywania zmian skupienia komórki, ponieważ to zdarzenie zostanie wyzwolone kilka razy nawet dla tej samej komórki w procesie wyszukiwania odpowiedniej komórki. Lepiej jest użyć do tego celu zdarzeń OnBeforeSelection lub OnSelection.

Różnice w porównaniu z Delphi

  • Zachowanie SelectCell i OnSelectCell jest prawdopodobnie inne — nie można tak naprawdę komentować różnic. W Lazarusie są one używane w funkcjonalności takiej jak AutoAdvance, która, o ile wiem, nie istnieje w Delphi.

Gdy powyższe dostosowanie nie wystarczy, siatki pochodne

Siatki pochodne zazwyczaj muszą zastąpić następujące metody:
DrawAllRows: Rysuje wszystkie widoczne wiersze.
DrawRow: Rysuje wszystkie komórki w rzędzie.
DrawRow rysuje wszystkie komórki w rzędzie, najpierw sprawdzając, czy komórka znajduje się w obszarze przycinania, i rysuje tylko komórkę, jeśli tak jest.
DrawCell:
DrawCellGrid:
DrawCellText:
DrawFocusRect:
(napisz do mnie).

Co dzieje się w metodzie TCustomGrid.Paint?

Poniższa lista pokazuje wewnętrzną kolejność wywołań metod dla malowania TCustomGrid (lub potomka). Każda pozycja na listach reprezentuje wywołania metod podczas operacji malowania. Powinno to pomóc w znalezieniu właściwego punktu do zmiany zachowania, jeśli chodzi o tworzenie klas potomnych z TCustomGrid.

  • DrawEdges: Rysuje zewnętrzną granicę siatki.
  • DrawAllRows (virtual): Rysuje wszystkie wiersze w widocznej części siatki. Jest to jedyna metoda wywoływana w procesie malowania, która jest zadeklarowana jako virtual (wirtualna).
    • DrawRow (virtual): Jest wywoływana dla każdego wiersza wewnątrz obecnego widoku.
      • DrawCell (virtual): Jest najpierw wywoływana dla każdej „normalnej” (tj. niestałej) komórki w rzędzie.
        • PrepareCanvas (virtual): Ustawia style rysowania na płótnie zgodnie z wizualnymi właściwościami bieżącej komórki.
        • DrawFillRect: Rysuje tło komórki ze stylami ustawionymi w PrepareCanvas.
        • DrawCellGrid (virtual): Rysuje linie obramowania komórki.
      • DrawFocusRect (virtual): W TCustomGrid ta metoda nic nie robi. W siatkach potomnych ta metoda jest używana do rysowania prostokąta skupienia wewnątrz aktywnej komórki.
      • DrawCell (virtual): (patrz powyżej) Jest wywoływana dla każdej stałej (fixed) komórki w widocznym obszarze wiersza.
  • DrawColRowMoving: Aktywna tylko podczas przenoszenia kolumny lub wiersza. Ta metoda rysuje linię wskazującą nową pozycję wiersza/kolumny.
  • DrawBorder: W razie potrzeby (Flat=TRUE i BorderStyle=bsSingle) rysuje wewnętrzną linię obramowania.

Dodatkowe metody rysowania w TCustomGrid

Te metody są zadeklarowane i (częściowo) zaimplementowane w TCustomGrid, ale nie są wywoływane bezpośrednio z tego miejsca. Są używane przez klasy potomne do rysowania zawartości komórki.

  • DrawCellText (virtual): Zapisuje/rysuje tekst, który jest przekazywany jako parametr do komórki. Tekst jest formatowany przy użyciu stylów aktywnych w Canvas.TextStyle (zobacz także PrepareCanvas).
  • DrawThemedCell (virtual): Jest używany tylko dla stałych komórek i tylko jeśli TitleStyle=tsNative. Rysuje tło komórki za pomocą ThemeServices.
  • DrawColumnText (virtual): Jest używany tylko dla komórek nagłówka kolumny.
    • DrawColumnTitleImage: Jeśli siatka ma przypisany TitleImageList i Columns.Title[x].Title.ImageIndex zawiera prawidłową wartość, to ten wybrany obraz jest rysowany w komórce.
    • DrawCellText : (patrz wyżej)
  • DrawTextInCell (virtual): Jest używany do „normalnych” (tj. niestałych) komórek. W TCustomGrid ta metoda nic nie robi. W siatkach potomnych ta metoda służy do rysowania zawartości komórek. W TSringGrid metoda ta wywołuje DrawCellText (patrz wyżej).

Metody rysowania wprowadzone przez TCustomDrawGrid

Jak widać, klasa bazowa TCustomGrid nie rysuje żadnej zawartości w komórkach. Odbywa się to w TCustomDrawGrid. TCustomDrawGrid nadpisuje metodę DrawCell w następujący sposób:

  • DrawCell (override):
    • PrepareCanvas: wywołuje odziedziczoną metodę z TCustomGrid.
    • DefaultDrawCell (virtual): Ta metoda jest wywoływana tylko wtedy, gdy procedura obsługi zdarzeń dla OnDrawCell NIE jest przypisana.
      • DrawFillRect / DrawThemedCell (od TCustomGrid): Rysuje tło komórki. Jeśli TitleStyle=tsNative, wówczas tło stałych komórek jest rysowane za pomocą DrawThemedCell.
      • DrawCellAutonumbering (virtual): Jeśli goFixedAutonumbering jest włączona w Options, to numery wierszy są rysowane w pierwszej ustalonej kolumnie przy użyciu TCustomGrid.DrawCellText.
      • DrawColumnText (z TCustomGrid): Jest wywoływana tylko dla komórek nagłówka kolumny (zobacz Dodatkowe metody rysowania w TCustomGrid< /tt>).
      • DrawTextInCell (z TCustomGrid): Jest wywoływana tylko dla 'normalnych' (tj. niestałych) komórek (zobacz Dodatkowe metody rysowania w TCustomGrid).
    • DrawCellGrid (virtual): Rysuje obramowanie komórki.

Operations

Focusing a cell

Focusing a cell in TStringGrid is easy. Note that counting starts from zero not 1. So to focus row 10, column 9, do:

StringGrid1.row := 9;
StringGrid1.col := 8;

Save and Retrieve Grid Content

The SaveToFile procedure allows you save the TStringGrid format, attributes & values to a XML file. Previously you must set the SaveOptios property as follow:

soDesign:     Save & Load ColCount,RowCount,FixedCols,FixedRows,
              ColWidths, RowHeights and Options (TCustomGrid)
soPosition:   Save & Load Scroll Position, Row, Col and Selection (TCustomGrid)
soAttributes: Save & Load Colors, Text Alignment & Layout, etc. (TCustomDrawGrid)
soContent:    Save & Load Text (TCustomStringGrid)

The LoadFromFile procedure allows you to load into a StringGrid instance, attributes, formats & values, from a XML file. First, you must set some of this options of the SaveOptions property (on your TStringGrid instance) SaveOptions

 soDesign:     Save & Load ColCount,RowCount,FixedCols,FixedRows,
               ColWidths, RowHeights and Options (TCustomGrid)
 soPosition:   Save & Load Scroll Position, Row, Col and Selection (TCustomGrid)
 soAttributes: Save & Load Colors, Text Alignment & Layout, etc. (TCustomDrawGrid)
 soContent:    Save & Load Text (TCustomStringGrid)

Example:

  1. First, go to menu "File -> New -> Application";
  2. Put an empty TStringGrid;
  3. Put a TButton and TOpenDialog;
  4. Add the event OnCreate for the Form;
  5. Add the event OnClick for the Button.
unit Unit1; 

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids,
  Buttons, StdCtrls, XMLCfg;

type

  { TForm1 }
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure Form1Create(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 

var
  Form1: TForm1; 

implementation

{ TForm1 }

procedure TForm1.Form1Create(Sender: TObject);
begin
 //sets the SaveOptions at creation time of the form 
 stringgrid1.SaveOptions := [soDesign,soPosition,soAttributes,soContent];
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
 //Ask if thew Execute method of the OpenDialog was launched 
 //when this occurs, the user selects an XML file to Load
 //wich name was stored in the FileName prop.

 if opendialog1.Execute then
 Begin
   //Clear the grid 
   StringGrid1.Clear;
   //Load the XML
   StringGrid1.LoadFromFile(OpenDialog1.FileName);
   //Refresh the Grid
   StringGrid1.Refresh;
 End;
end;

initialization
  {$I unit1.lrs}

end.

The sample xml file: (Copy the text below into a txt file. Don't forget put the xml header :-))

<?xml version="1.0"?>
<CONFIG>
  <grid version="3">
    <saveoptions create="True" position="True" content="True"/>
    <design columncount="2" rowcount="5" fixedcols="1" fixedrows="1" defaultcolwidth="64" defaultRowHeight="20">
      <options>
        <goFixedVertLine value="True"/>
        <goFixedHorzLine value="True"/>
        <goVertLine value="True"/>
        <goHorzLine value="True"/>
        <goRangeSelect value="True"/>
        <goDrawFocusSelected value="False"/>
        <goRowSizing value="False"/>
        <goColSizing value="False"/>
        <goRowMoving value="False"/>
        <goColMoving value="False"/>
        <goEditing value="False"/>
        <goTabs value="False"/>
        <goRowSelect value="False"/>
        <goAlwaysShowEditor value="False"/>
        <goThumbTracking value="False"/>
        <goColSpanning value="False"/>
        <goRelaxedRowSelect value="False"/>
        <goDblClickAutoSize value="False"/>
        <goSmoothScroll value="True"/>
      </options>
    </design>
    <position topleftcol="1" topleftrow="1" col="1" row="1">
      <selection left="1" top="1" right="1" bottom="1"/>
    </position>
    <content>
      <cells cellcount="10">
        <cell1 column="0" row="0" text="Title Col1"/>
        <cell2 column="0" row="1" text="value(1.1)"/>
        <cell3 column="0" row="2" text="value(2.1)"/>
        <cell4 column="0" row="3" text="value(3.1)"/>
        <cell5 column="0" row="4" text="value(4.1)"/>
        <cell6 column="1" row="0" text="Title Col2"/>
        <cell7 column="1" row="1" text="value(1.2)"/>
        <cell8 column="1" row="2" text="value(2.2)"/>
        <cell9 column="1" row="3" text="value(3.2)"/>
        <cell10 column="1" row="4" text="value(4.2)"/>
      </cells>
    </content>
  </grid>
</CONFIG>

--Raditz 21:06, 11 Jan 2006 (CET) from ARGENTINA

Grid Cell Editors

The grid uses cell editors to change the content of cells.

For a specialized grid like TStringGrid, the editor is the usual single line text editor control, but sometimes it's desirable to have other means to enter information. For example, to call the open file dialog to find the location of a file so the user doesn't have to type the full path manually; if the text in the cell represents a date, it would be more friendly if we could popup a calendar so we can choose a specific date easily.

Sometimes the information the user should enter in a cell is restricted to a limited list of words; in this case typing the information directly might introduce errors and validating routines might need to be implemented. We can avoid this by using a cell editor that presents the user with a list containing only the legal values.

This is also the case for generic grids like TDrawGrid where the user needs some kind of structure to hold the data that will be shown in the grid. In this situation, the information that is entered in the cell editor updates the internal structure to reflect the changes in the grid.

Builtin cell editors

The grids.pas unit already includes some of the most used cell editors ready for use in grids. It is also possible to create new cell editors (custom cell editors) if the built-in editors are not appropiate for a specific task.

The builtin cell editors are Button, Edit, and Picklist.

Using cell editors

Users can specify what editor will be used for a cell using one of two methods.

  1. Using a custom column and selecting the ButtonStyle property of the column. In this method the user can select the style of the editor that will be shown. Available values are: cbsAuto, cbsEllipsis, cbsNone, cbsPickList, cbsCheckboxColumn, cbsButtonColumn.
  2. Using OnSelectEditor grid event. Here the user specifies in the Editor parameter which editor to use for a cell identified for column aCol and row ARow in a TCustomDrawGrid derived grid or TColumn in TCustomDBGrid. For this purpose there is a useful public function of grids, EditorByStyle() that takes as parameter one of the following values: cbsAuto, cbsEllipsis, cbsNone, cbsPickList, cbsCheckboxColumn, cbsButtonColumn. This method takes precedence over the first one using custom columns. A Custom cell editor can be specified here. This event is also the place to setup the editor with values specific to the cell, row or column.

Description of editor styles

The following is a description of the editor styles. They are enumerated values of type TColumnButtonStyle and so they are prefixed by 'cbs'. This type was used to remain compatible with Delphi's DBGrid.

  • cbsAuto
This is the default editor style for TCustomGrid derived grids. The actual editor class that will be used to edit the cell content depends on several factors. For TCustomGrids it uses a TStringCellEditor class derived from TCustomMaskEdit. This editor is specialized to edit single line strings. It is then used in TStringGrid and TDrawGrid by default. When using Custom Columns, if the programmer filled the Column's PickList property, this behaves as if cbsPickList editor style was set. For a TCustomDBGrid that has a field of type boolean, it behaves as if cbsCheckBoxColumn editor style was specified. This is the recommended value for Custom Cell Editors. TODO: related OnEditingDone.
  • cbsEllipsis
This editor style is the most generic one. When used, a button appears in the editing cell and programmers could use the OnEditButtonClick grid event to detect when the user has pressed the button and take any action programmed for such a cell. For example a programmer could use this editor style to pop up a calendar dialog to allow the user easily to select a specific date. Other possibilities could be to show a file open dialog to find files, a calculator so user can enter the numeric result of calcs, etc.
OnEditButtonClick is just a notification, to find out in which cell a button has been clicked by taking a look at the grid.Row and grid.Col properties.
A DBGrid has specific properties to retrieve the active column or field and because this event occurs in the active record, it could update the information in the active field.
This editor style is implemented using TButtonCellEditor, a direct descendant of TButton.
  • cbsNone
This editor style instructs the grid not to use any editor for a specific cell or column; it behaves then, as if the grid were readonly for such a cell or column.
  • cbsPickList
Used to present the user with a list of values that can be entered. This editor style is implemented using TPickListCellEditor, a component derived from TCustomComboBox. The list of values that are shown is filled in one of two ways depending on the method used to select the editor style.
  1. When using custom columns, programmers can enter a list of values using the column's PickList property. [FOR BEGINNERS: TODO: exact procedure to edit the list]
  2. In OnSelectEditor, programmers get the TPickListCellEditor instance using the function EditorByStyle(cbsPickList). An example would be:
var Lst:TPickListCellEditor; 
  begin [...] 
    Lst:=TPickListCellEditor(EditorByStyle(cbsPickList)); 
    Lst.clear; 
    Lst.Items.add('One'); 
    Lst.items.add('Two'); 
    Editor:=Lst; 
  end;
The value in a TStringGrid grid will automatically reflect the value selected. If necessary the programmer could detect the moment the value is selected by writing an event handler for the grid's OnPickListSelect event, so additional steps can be taken (for example, to process the new value). TODO: related OnEditingDone.
  • cbsCheckboxColumn
It can be useful when the data content associated with the column is restricted to a pair of values, for example, yes-no, true-false, on-off, 1-0, etc. Instead of forcing the user to type the values for this kind of data in a StringCellEditor or to choose one from a list, cbsCheckboxColumn is used to modify the data of a column by using a checkbox representation that the user can toggle by using a mouse click or pressing the SPACE key.
If a columns' ButtonStyle property is set to cbsAuto and DBGrid detects that the field associated with the column is a boolean field, then the grid uses this editor style automatically. This automatic selection can be disabled or enabled using DBGrid's OptionsExtra property; setting dgeCheckboxColumn element to false disables this feature.
The values that are used to recognize the checked or unchecked states are set in a column's properties ValueChecked and ValueUnchecked.
At any moment, the field value can be in one to three states: Unchecked, Checked or Grayed. Internally these states are identified by the following values of type TDBGridCheckBoxState: gcbpUnChecked, gcbpChecked and gcbpGrayed.
This editor style doesn't use real TCheckbox components to handle user interaction: the visual representation is given by three built-in bitmap images that corresponds to the possible states of checkbox. The used bitmaps can be customized by writing a handler for DBGrid event OnUserCheckboxBitmap; the handler of this event gets the state of the checkbox in the parameter CheckedState of type TDBGridCheckboxState and a bitmap parameter that the programmer could use to specify custom bitmaps.
  • cbsButtonColumn
This editor style is used to show a button on every cell on column. Like in the case of cbsCheckboxColumn this editor do not use real buttons, the appearance is defined by current widgetset theme.
The user knows what particular button was pressed by handling the grid's OnEditButtonClick and checking grid's col and row. Note that in this particular case, grid's col and row do not identify the currently selected cell, but the cell of the clicked button. Once the OnEditButtonClick event has been handled, and if the user has not modified the grid's col or row in this handler, the grid automatically resets the col and row to reflect the currently selected cell. While handling the OnEditButtonClick the current grid selection is available in grid.Selection which is a TRect property, left and right represent Column indexes, Top and Bottom are row indexes.
The button's caption is the corresponding cell string.

Example: How to set a custom cell editor

See lazarus/examples/gridcelleditor/gridcelleditor.lpi

Example: How to add a button editor

// Conditionally show button editor in column index 1 or 2 if 
// cell in column index 1 is empty 
procedure TForm1.StringGrid1SelectEditor(Sender: TObject; aCol, aRow: Integer; 
  var Editor: TWinControl);
begin
  if (aCol = 1) or (aCol = 2) then
    if StringGrid1.Cells[1,aRow] = '' then
    begin
      Editor := StringGrid1.EditorByStyle(cbsEllipsis);
    end;
  end;

// Triggering Action ...
procedure TForm1.StringGrid1EditButtonClick(Sender: TObject);
begin
  if StringGrid1.Col = 1 then Showmessage('column 1 editor clicked');
  if StringGrid1.Col = 2 then Showmessage('column 2 editor clicked');
end;

Example: How to align column text in StringGrids

  procedure TForm1.StringGrid1PrepareCanvas(sender: TObject; aCol, aRow: Integer;
    aState: TGridDrawState);
  var
    MyTextStyle: TTextStyle;
  begin
    if (Col=2) or (Col=3) then
    begin
      MyTextStyle := StringGrid1.Canvas.TextStyle;
      if Col=2 then
        MyTextStyle.Alignment := taRightJustify 
      else 
      if Col=3 then
        MyTextStyle.Alignment := taCenter;
      StringGrid1.Canvas.TextStyle := MyTextStyle;
    end;
  end;

Validating Entered Values

Lazarus version 0.9.29 introduces StringGrid OnValidateEntry event of type TValidateEntryEvent which has following declaration:

  TValidateEntryEvent =
    procedure(sender: TObject; aCol, aRow: Integer;
              const OldValue: string; var NewValue: string) of object;
aCol,aRow are the cell coordinates of cell being validated.
OldValue is the value that was in cells[aCol,aRow] before editing started.
NewValue is the value that will be finally inserted in cells[aCol,aRow].

Because of the way StringGrid works by setting the cell value while user is editing (see grid's OnSetEditText event and SetEditText method) when the OnValidateEntry event triggers, the cell already contains the entered value being valid or not, using event arguments OldValue and NewValue the cell value can be validated and changed accordingly.

Usually validation occurs when user has moved to another cell, if validation fails is desireable to keep the cell editor visible so the entered value can be corrected by user. To let the grid know that validation has failed an exception needs to be raised, the grid will handle the exception to Application.HandleException and any movement is cancelled. For example, suppose that cell[1,1] should hold only values 'A' or 'B' validation could be made with:

 procedure TForm1.GridValidateEntry(sender: TObject; aCol,
   aRow: Integer; const OldValue: string; var NewValue: String);
 begin
   if (aCol=1) and (aRow=1) then begin
     if grid.Cells[aCol,aRow]<>'A') and grid.Cells[aCol,aRow]<>'B') then begin
       // set a new valid value so user can just press RETURN to continue for example.
       NewValue := 'A';
       // another option is reverting to previous cell value (which is assumed to be valid)
       // NewValue := OldValue;
       raise Exception.Create('Only A or B are allowed here');
     end else begin
       // if no exception is raised, is assumed that value is valid, yet if necessary
       // final value can be changed by filling NewValue with a different value
       
       // computer knows better :)
       if grid.Cells[1,1]='A' then 
         NewValue := 'B' 
       else 
         NewValue := 'A';
     end;
   end;
 end;

Sorting Columns or Rows

StringGrid has built-in sorting capabilities using SortColRow() method, the first parameter is a boolean value which indicates true if a column is to be sorted or false for a row, the next parameter is the column or row index, the next parameters are optional and selects subrange of rows (for column sorting) or columns (for row sorting) to be sorted, if the last parameters are not specified, the whole column or row is sorted. Sorting uses QuickSort algorithm, it could be changed if a descendant grid overrides the sort() method and calls doCompareCells for cell compare.

By default it sorts cell content as strings either in ascending or descending order which is selectable with property SortOrder, by default it uses Asceding order.

  // sort column 3 in ascending order
  grid.SortColRow(true, 3);

  // sort column 3 in descending order, skip fixed rows a top
  grid.SortOrder := soDescending; // or soAscending
  grid.SortColRow(true, 3, grid.FixedRows, grid.RowCount-1);

For custom sorting of numbers, dates, states, etc. StringGrid has the OnCompareCells event which users can handle for example this way:

procedure TForm1.GridCompareCells(Sender: TObject; ACol, ARow, BCol,
  BRow: Integer; var Result: integer);
begin
  result := StrToIntDef(Grid.Cells[ACol,ARow],0)-StrToIntDef(Grid.Cells[BCol,BRow],0);
  // result will be either <0, =0, or >0 for normal order
  // for inverse order, just invert the sign of result
  // result := -result;
end;

Please notice that SortOrder do not work if OnCompareCells is used.

Tłumaczenie

Na język polski przełożył: --Sławomir Załęcki 21:10, 10 September 2010 (CEST)