Sign in Join
Wiki copytemporary

Grids Reference Page/pl: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11Strona referencyjna siatek Grid
22
33## Intencje
44
55Ten 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:
66
771. Przedstawić komponenty siatki osobom z niewielkim lub żadnym doświadczeniem w Delphi.
882. Udokumentować różnice w odniesieniu do komponentów siatek Delphi.
993. Udokumentować nową funkcjonalność w siatkach Lazarusa.
10104. Utworzyć referencje i przykłady dla tych komponentów.
1111
1212## Wprowadzenie
1313
1414Siatka (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.
1515
1616Ilość 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.
1717
1818Biorą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](http://lazarus-ccr.sourceforge.net/docs/lcl/grids/tstringgrid.html)
1919
2020## Drzewo dziedziczenia
2121
22-`                     `[[TCustomControl]]\
23-`                             |`\
24-`                             |`\
25-`                        TCustomGrid`\
26-`                             |`\
27-`               +-------------+------------+`\
28-`               |                          |`\
29-`         TCustomDrawGrid             TCustomDbGrid`\
30-`               |                          |`\
31-`      +--------+--------+                 |`\
32-`      |                 |              `[[TDBGrid]]\
33-`  `[[TDrawGrid]]`      TCustomStringGrid                `\
34-`                        |`\
35-`                        |`\
36-`                   `[[TStringGrid]]
22+```text
23+ TCustomControl
24+ |
25+ |
26+ TCustomGrid
27+ |
28+ +-------------+------------+
29+ | |
30+ TCustomDrawGrid TCustomDbGrid
31+ | |
32+ +--------+--------+ |
33+ | | TDBGrid
34+ TDrawGrid TCustomStringGrid
35+ |
36+ |
37+ TStringGrid
38+```
3739
3840## Pierwszy przykład
3941
4042Ponieważ 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.
4143
42441. Stwórz nową aplikację.
4345 - Z menu głównego wybierz: Projekt-\>Nowy projekt...
4446 - W oknie dialogowym Utwórz nowy projekt wybierz Aplikacja i naciśnij „OK”
4547 - Zostanie wyświetlony nowy pusty formularz.
46482. Umieść siatkę (grid) na formularzu
4749 - Z palety komponentów wybierz zakładkę „Additional”
4850 - Kliknij ikonę TStringGrid ![](/wiki-images/6/67/Tstringgrid.png)
4951 - Kliknij formularz w lewym górnym rogu. Pojawi się nowa pusta siatka.
50523. Umieść przycisk na formularzu
5153 - Z palety komponentów wybierz zakładkę „Standard”
5254 - Kliknij ikonę TButton ![](/wiki-images/b/b2/Tbutton.png)
5355 - Kliknij na pusty obszar formularza. Pojawi się nowy przycisk.
5456
5557Kliknij dwukrotnie przycisk z kroku 3 i zapisz następujący kod w module obsługi przycisku kliknięcia:
5658
5759\#*
5860
5961``` Pascal
6062StringGrid1.Cells[1,1] := 'Witaj Świecie!';
6163```
6264
63651. Uruchom program, klikając ikonę odtwarzania ![](/wiki-images/8/85/Menu_run.png)
6466 - 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)
6567
6668## Różnice pomiędzy komponentami siatki Lazarusa i Delphi
6769
6870Obecne 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.
6971
7072Na 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.
7173
7274### Różnice
7375
7476Znane różnice wymieniono poniżej (kolejność nie ma znaczenia).
7577
7678- Edytor komórek (Cell Editor)
7779- Zachowanie podczas projektowania
7880- Pewne różnice występują podczas rysowania komórek, zobacz sekcję [Dostosowywanie siatek](https://wiki.freepascal.org/Grids_Reference_Page/pl#Dostosowywanie_siatek).
7981
8082### Nowe funkcje
8183
8284- Kolumny
8385- Zdarzenia
8486- Edytor siatki (Grid Editor)
8587
8688### Sposoby na to, by siatka Lazarus była bardziej zgodna z Delphi
8789
8890Oto 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.
8991
9092Moż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.
9193
9294- \[Projekt\] TitleStyle := tsStandard;
9395- \[Projekt\] DefaultRowHeight := 24;
9496- \[Kod\] EditorBorderStyle := bsNone; //to może działać tylko w Windows
9597- \[Kod\] UseXORFeatures := true;
9698- \[Kod\] AllowOutBoundEvents := False; //rewizja SVN r10992 lub nowsza
9799- \[Kod\] FastEditing := False; //obsługiwane w dbgrid. StringGrid wymaga wersji SVN r10992 lub nowszej
98100- \[Projekt\] AutoAdvance := aaNone;
99101
100102## Charakterystyka siatek
101103
102104### Informacja
103105
104106Punktem wyjścia dla referencji o TCustomGrid, TDrawGrid, TCustomDrawGrid, TCustomStringGrid i TStringGrid jest [referencje modułu Grids.pas](http://lazarus-ccr.sourceforge.net/docs/lcl/grids/index.html)
105107
106108Natomiast dla TCustomDBGrid i TDBgrid jest [referencje modułu DBGrids.pas](http://lazarus-ccr.sourceforge.net/docs/lcl/dbgrids/index.html)
107109
108110Zazwyczaj 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.
109111
110112TODO: Dalsza część tego rozdziału zniknie, a jego zawartość zostanie przeniesiona do [referencje modułu Grids.pas](http://lazarus-ccr.sourceforge.net/docs/lcl/grids/index.html)
111113
112114### TCustomGrid
113115
114116Wszystko zobaczysz w: [[doc:lcl/grids/tcustomgrid.html|Referencje TCustomGrid]]
115117
116118#### Właściwość AllowOutboundEvents
117119
118120Wł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.
119121
120122#### Właściwość Columns
121123
122124Lazarus 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.
123125
124126Kolumny 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**.
125127
126128Na przykład, jeśli mamy siatkę bazową z ColCount := 5 i FixedCols := 2 i wykonamy:
127129
128130- Dodaj 3 niestandardowe kolumny, to siatka bazowa będzie dokładnie taka sama, jak poprzednio, 2 stałe kolumny i 3 normalne kolumny.
129131- Dodaj 1 niestandardową kolumnę, to siatka bazowa będzie miała ColCount := 3, czyli 2 stałe kolumny i 1 normalną kolumnę.
130132- Dodaj 4 niestandardowe kolumny, to siatka bazowa będzie miała ColCount := 6, czyli 2 stałe kolumny i 4 normalne kolumny.
131133
132134Z tego możemy wywnioskować, że:
133135
134136- Stałe właściwości lub liczba kolumn nie są odpowiednio ulepszane ani modyfikowane przez kolumny niestandardowe.
135137- **grid.ColCount** zwykle różni się od **grid.Columns.Count** (**grid.ColCount**=**grid.Columns.Count** tylko wtedy, gdy ' *FixedCols*'=0)
136138
137139W 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.
138140
139141W czasie wykonywania programu, kolumny można modyfikować za pomocą kodu w następujący sposób:
140142
141143``` pascal
142144 var
143145 c: TGridColumn;
144146 begin
145147 // dodaj niestandardową kolumnę siatki
146148 c := Grid.Columns.Add;
147149 // modyfikuj kolumnę
148150 c.title.caption := 'Price'; // Ustaw tytuły kolumn
149151 c.align := taRightJustify; // Wyrównaj zawartość kolumny do prawej
150152 c.color := clMoneyGreen; // Zmień domyślny kolor na clMoneyGreen
151153 c.Index := 0; // Niech to będzie pierwsza kolumna
152154 // uzyskać dostęp do istniejącej kolumny
153155 grid.columns[0].Width := 60; // Zmień szerokość kolumny 0 na 60 pikseli
154156 // usuń istniejącą kolumnę
155157 grid.columns.delete(0); // Usuń kolumnę 0
156158 ....
157159 end;
158160```
159161
160162Dodatkowo, 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ą.
161163
162164Obecnie nie ma planów, aby siatki wykorzystywały tylko kolumny niestandardowe.
163165
164166#### Właściwość AutoFillColumns
165167
166168Czę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.
167169
168170W 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`.
169171
170172#### Procedura SaveToFile(AFileName: String)
171173
172174Zapisuje siatkę do pliku XML. Właściwość `SaveOptions` określa, co dokładnie ma zostać zapisane:
173175
174176``` Pascal
175177type
176178 TGridSaveOptions = (
177179 soDesign, // Zapisz strukturę siatki (liczba kolumn/wierszy i opcje - Options)
178180 soAttributes, // Zapisz atrybuty siatki (czcionka - Font, pędzel - Brush, styl tekstu TextStyle)
179181 soContent, // Zapisz zawartość siatki (tekst w StringGrid)
180182 soPosition // Zapisz kursor siatki i pozycję zaznaczenia
181183 );
182184 TSaveOptions = set of TGridSaveOptions;
183185```
184186
185187#### Procedura LoadFromFile(AFileName: String)
186188
187189Ładuje plik XML utworzony przez `SaveToFile`. Ponownie, `SaveOptions` określają, co dokładnie ma zostać załadowane z pliku.
188190
189191### TCustomDBGrid
190192
191193TCustomDBGrid jest podstawą dla TDBGrid.
192194
193195Nie ujawniają właściwości Col i Row. Aby przejść do określonej kolumny, użyj np. właściwość SelectedIndex.
194196
195197Ciekawą metodą publiczną jest AutoAdjustColumns.
196198
197199#### Procedura AutoAdjustColumns
198200
199201Ta procedura ustawia szerokość kolumny na rozmiar najszerszego znalezionego tekstu. Można go używać po załadowaniu zestawu danych/ustawieniu go jako Aktywny - Active.
200202
201203Jednak w przeciwieństwie do TCustomStringGrid.AutoAdjustColumns (patrz poniżej), spowoduje to ustawienie bardzo szerokich kolumn, chyba że masz włączoną właściwość dgAutoSizeColumns.
202204
203205#### Procedura InplaceEditor
204206
205207Zobacz 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?*
206208
207209``` pascal
208210
209211procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: char);
210212var
211213 S: String;
212214begin
213215 if (Key in [',','.']) then
214216 begin
215217 //w przeciwieństwie do Delphi nie wszystkie edytory InPlaceEditors są edytorami typu string, więc sprawdź!
216218 if (DBGrid1.InplaceEditor is TStringCellEditor) then
217219 begin
218220 S := TStringCellEditor(DBGrid1.InplaceEditor).EditText;
219221 if Pos(',',S) > 0 then
220222 Key := #0
221223 else
222224 Key := ',';
223225 end;
224226 end;
225227end;
226228```
227229
228230### TCustomStringGrid
229231
230232Klasa 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.
231233
232234Następujące właściwości lub metody są publiczne i są również dostępne dla TStringGrid.
233235
234236Zobacz pełną [[doc:lcl/grids/tcustomstringgrid.html|dokumentację TCustomStringGrid]]
235237
236238#### Procedura AutoSizeColumn(aCol: Integer)
237239
238240Ta 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.
239241
240242#### Procedura AutoAdjustColumns lub AutoSizeColumns
241243
242244Automatycznie 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.
243245
244246#### Procedura Clean; overload;
245247
246248Czyści wszystkie komórki siatki, także te stałe (typu fixed).
247249
248250#### Procedura Clean(CleanOptions: TGridZoneSet); overload;
249251
250252Czyści wszystkie komórki w siatce wskazane w parametrze CleanOptions. Zobacz TGridZoneSet aby uzyskać więcej informacji. Poniżej kilka przykładów:
251253
252254- Czyści wszystkie komórki: grid.Clean(\[\]); (działa tak samo jak grid.clean)
253255- Czyści wszystkie normalne (nie stałe - non fixed) komórki: grid.Clean(\[gzNormal\]);
254256- Czyści wszystkie komórki oprócz nagłówków kolumn siatki: Grid.Clean(\[gzNormal, gzFixedRows\]);
255257
256258#### Procedura Clean(StartCol,StartRow,EndCol,EndRow: integer; CleanOptions:TGridZoneSet); overload;
257259
258260Wykonuje to samo co Clean(CleanOptions:TGridZoneSet), ale jej działanie ograniczone jest obszarem określonym parametrami StartCol, StartRow, EndCol i EndRow. Przykład:
259261
260262- 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.
261263
262264#### Procedura Clean(aRect: TRect; CleanOptions: TGridZoneSet); overload;
263265
264266Wykonuje 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,\[\]);
265267
266268==== Procedura SaveToCSVFile(AFileName: string; ADelimiter:Char=','; WithHeader:boolean=true); ====
267269
268270Zapisuje zawartość siatki w pliku w formacie tekstowym, gdzie wartości są rozdzielone przecinkami (CSV) (dodanym w Lazarus r32179).
269271
270272Argument 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.
271273
272274ADelimiter (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.
273275
274276Parametr 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.
275277
276278Jeś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.
277279
278280Normalne wyjście danych CSV rozpocznie się od pierwszego niestałego (Non-Fixed) wiersza w siatce.
279281
280282==== Procedura LoadFromCSVFile(AFileName: string; ADelimiter:Char=','; WithHeader:boolean=true); ====
281283
282284Wczytuje zawartość siatki z pliku w formacie CSV (dodanym w Lazarus r32179).
283285
284286Kolumny 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.
285287
286288Argument *AFileName* określa nazwę pliku źródłowego z zawartością CSV.
287289
288290Opcjonalny 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ć ;
289291
290292Parametr *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.
291293
292294Jeś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*.
293295
294296#### Właściwość Cols\[index: Integer\]: TStrings read GetCols write SetCols;
295297
296298Pobierz/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.
297299
298300##### Przykłady
299301
300302- Przykład wstawiania: Wstawia treść do trzeciej kolumny siatki z kontrolki ListBox:
301303
302304``` pascal
303305Grid.Cols[2] := ListBox1.Items;
304306```
305307
306308- Przykład pobrania: Wstawia treść kontrolki ListBox z kolumny siatki o indeksie 4:
307309
308310``` pascal
309311procedure TForm1.FillListBox1;
310312var
311313 StrTempList: TStringList;
312314begin
313315 StrTempList := TStringList(Grid.Cols[4]);
314316 if StrTempList<>nil then begin
315317 ListBox1.Items.Assign(StrTempList);
316318 StrTempList.Free;
317319 end;
318320end;
319321```
320322
321323##### Uwagi
322324
323325Ta 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.
324326
325327Oznacza 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.
326328
327329Zobacz powyższy przykład pobrania.
328330
329331#### Właściwość Rows\[index: Integer\]: TStrings read GetRows write SetRows;
330332
331333Pobierz/ustaw listę ciągów string z/do wiersza siatki o danym indeksie, począwszy od indeksu kolumny 0 do kolumny ColCount-1.
332334
333335##### Uwagi
334336
335337Ta 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.
336338
337339Oznacza 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.
338340
339341##### Przykłady
340342
341343- Przykład ustawiania: Ustaw zawartość trzeciego wiersza siatki jako zawartość ListBox:
342344
343345``` Pascal
344346Grid.Rows[2] := ListBox1.Items;
345347```
346348
347349- Przykład pobrania: Ustaw zawartość pola listy z 4 indeksu wiersza siatki:
348350
349351``` pascal
350352procedure TForm1.FillListBox1;
351353var
352354 StrTempList: TStringList;
353355begin
354356 StrTempList := TStringList(Grid.Rows[4]);
355357 if StrTempList<>nil then begin
356358 ListBox1.Items.Assign(StrTempList);
357359 StrTempList.Free;
358360 end;
359361end;
360362```
361363
362364- Przykład, który nie działa, oraz jego poprawka: Pobrana lista ciągów jest tylko do odczytu
363365
364366``` pascal
365367 // te dwa przykłady nie zadziałają i spowodują wycieki pamięci,
366368 // ponieważ zwrócone listy ciągów nie są zwalniane
367369 Grid.Rows[1].CommaText := '1,2,3,4,5';
368370 Grid.Rows[2].Text := 'a'+#13#10+'s'+#13#10+'d'+#13#10+'f'+#13#10+'g';
369371
370372 // naprawienie pierwszego przypadku
371373 Lst:=TStringList.Create;
372374 Lst.CommaText := '1,2,3,4,5';
373375 Grid.Rows[1] := Lst;
374376 Lst.Free;
375377```
376378
377379#### Właściwość UseXORFeatures
378380
379381Właściwość typu Boolean, wartość domyślna: False;
380382
381383Ta 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ą [[FocusColor property|właściwości FocusColor]]
382384
383385Kontroluje 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ą.
384386
385387### TValueListEditor
386388
387389[[TValueListEditor]] to kontrolka (formant) pochodzący z TCustomStringGrid i służy do edycji par typu klucz-wartość.
388390
389391#### Właściwość DisplayOptions
390392
391393Kontroluje różne aspekty wyglądu TValueListEditor.
392394
393395#### Właściwość TitleCaptions
394396
395397Ustawia 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.
396398
397399#### Właściwość Strings
398400
399401Zapewnia dostęp do listy ciągów zawierających pary klucz-wartość.\
400402Pary klucz-wartość muszą mieć format typu:\
401403'NazwaKlucza=Wartość'
402404
403405#### Właściwość ItemProps
404406
405407Możesz użyć tej właściwości, aby kontrolować sposób edytowania elementów w kolumnach „Value” (Wartość).\
406408Jest to kontrolowane przez ustawienie właściwości EditStyle i ReadOnly elementu ItemProp.
407409
408410#### Właściwość KeyOptions
409411
410412KeyOptions to zbiór wartości porządkowych TKeyOptions kontrolujących, czy użytkownik może modyfikować zawartość kolumny „Key” (Klucz).
411413
412414- KeyEdit: użytkownik może edytować nazwę klucza
413415- KeyAdd: użytkownik może dodawać klucze (przez wciśnięcie klawisza Insert w siatce). KeyAdd wymaga KeyEdit.
414416- KeyDelete: użytkownik może usuwać pary klucz-wartość (przez naciśnięcie kombinacji Ctrl+Delete).
415417- KeyUnique: jeśli ustawione, klucze muszą mieć unikalne nazwy. Próba wprowadzenia zduplikowanego klucza spowoduje zgłoszenie wyjątku.
416418
417419#### Właściwość DropDownRows
418420
419421Jeś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.
420422
421423#### Funkcja DeleteRow
422424
423425Usuwa parę Klucz-Wartość wiersza o podanym indeksie, całkowicie usuwając wiersz.
424426
425427#### Funkcja InsertRow
426428
427429Wstawia wiersz w siatce i ustawia parę Klucz-Wartość. Zwraca indeks nowo wstawionego wiersza.
428430
429431#### Funkcja IsEmptyRow
430432
431433Zwraca wartość True, jeśli komórki indeksowanego wiersza są puste (Keys\[aRow\]=*; Values\[aRow\]=*).
432434
433435#### Funkcja FindRow
434436
435437Zwraca indeks wiersza, który ma określoną nazwę klucza.
436438
437439#### Funkcja RestoreCurrentRow
438440
439441Cofa edycję w bieżącym wierszu (jeśli edytor jest nadal aktywny). Dzieje się tak, gdy użytkownik naciśnie klawisz Escape.
440442
441443#### Zmienione zachowanie niektórych właściwości pochodzących z TCustomStringGrid
442444
443445##### Właściwość Options
444446
445447Ze względu na charakter TValueListEditor jego właściwość Options ma pewne ograniczenia
446448
447449- goColMoving nie jest dozwolony w opcjach (nie można go ustawić).
448450- goAutoAddRows można ustawić tylko wtedy, gdy KeyAdd jest włączony w KeyOptions. Ustawienie KeyAdd automatycznie ustawi goAutoAddRows.
449451- goAutoAddRowsSkipContentCheck jest niedozwolone (na razie powoduje awarię w TValueListeditor: wymaga naprawy).
450452
451453##### Właściwość FixedRows
452454
453455Może mieć wyłącznie wartość równą 1 (pokaż tytuły kolumn) lub 0 (nie pokazuj tytułów kolumn).
454456
455457##### Właściwość ColCount
456458
457459Może mieć wyłącznie wartość równą 2.
458460
459461##### Właściwość Objects
460462
461463Uwaga! Nie zaleca się używania tej właściwości w ogóle.\
462464Kiedy jakiś (wewnętrzny) kod manipuluje właściwością Strings, zmiany dla Objects zostaną utracone.
463465
464466#### Ogólne uwagi dotyczące korzystania z TValueListEditor
465467
466468Podczas manipulowania zawartością ValueListEditor (siatki) można bezpośrednio manipulować podstawową właściwością Strings.\
467469Pamię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.\
468470
469471Jeś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().\
470472
471473Próba użycia metod z klasy przodka do manipulowania wierszami lub kolumnami (np. Columns.Add) może spowodować awarię.
472474
473475#### Zapisywanie i ładowanie zawartości TValueListEditor
474476
475477##### Korzystanie z właściwości Strings
476478
477479Jeś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.\
478480W przypadku LoadFromFile właściwość `RowCount` zostanie automatycznie dostosowana.\
479481Ró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).
480482
481483##### Korzystanie z TValueList.SaveToFile i TValueList.LoadFromFile
482484
483485When using SaveToFile and LoadFromFile you get the additional benefits of also being able to save and load the layout, like with other grids.\
484486SaveToFiel will also save information about wether or not the TValueListEditor uses ColumnTitles, and if so, it saves them.\
485487
486488In 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.\
487489If the file does not seem to be a valid TValueListEditor grid file, and exception is raised.\
488490
489491TValueList.SaveToFile and TValueList.LoadFromFile do not work correctly in Lazarus versions \<= 2.1 r62044.
490492
491493Korzystają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.\
492494SaveToFile zapisze również informacje o tym, czy TValueListEditor używa ColumnTitles, a jeśli tak, zapisuje je.\
493495
494496W 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.\
495497Jeśli plik nie wydaje się być prawidłowym plikiem siatki TValueListEditor, zgłaszany jest wyjątek.\
496498
497499TValueList.SaveToFile i TValueList.LoadFromFile nie działają poprawnie w wersjach Lazarusa \<= 2.1 r62044.
498500
499501##### Korzystanie z metod SaveToCSVFile i LoadFromCSV
500502
501503Te metody nie powinny być obecnie używane, ponieważ w przypadku TValueListEditor są one wadliwe.
502504
503505## Praca z siatkami
504506
505507### Dostosowywanie siatek
506508
507509Komponenty Grid pochodzą z klasy [TCustomControl](http://lazarus-ccr.sourceforge.net/docs/lcl/controls/tcustomcontrol.html) 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).
508510
509511### Właściwości i Zdarzenia dostosowujące siatek
510512
511513Niektó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:
512514
513515- **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.
514516- **Color.** Ta właściwość ustawia podstawowy kolor używany do rysowania tła niestałych (Non-Fixed) komórek.
515517- **FixedColor.** Jest to kolor używany do rysowania tła dla stałych komórek (Fixed).
516518- **Flat.** Ta właściwość wyłącza trójwymiarowy wygląd stałych komórek.\
517519- **TitleFont.** Czcionka używana do rysowania tekstu w stałych komórkach.\
518520- **TitleStyle.** Ta właściwość zmienia wygląd 3D stałych komórek, istnieją 3 ustawienia:
519521 - *tsLazarus.* To jest domyślny wygląd preferowany przez Lazarusa
520522 - *tsNative.* Ta wartość próbuje ustawić wygląd zgodny z bieżącym motywem zestawu widżetów.
521523 - *tsStandard.* Ten styl jest bardziej kontrastowy, podobnie jak siatki Delphi.
522524- **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.
523525- **BorderColor.** Ustawia kolor obramowania siatki używany, gdy Flat:=True i BorderStyle:=bsSingle.
524526- **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.\
525527- **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.
526528- **FocusRectVisible.** Włącza/wyłącza rysowanie skupionej komórki.
527529- **GridLineColor.** Kolor linii siatki w obszarze niestałych komórek.
528530- **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*.
529531- **SelectedColor.** Kolor używany do rysowania tła komórki na wybranych, zaznaczonych komórkach.
530532- **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.
531533- **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.
532534- **AutoAdvance.** Determinuje to, gdzie ma zostać przeniesiony kursor komórki po naciśnięciu klawisza Enter lub po zakończeniu edycji.
533535- **TabAdvance.** Determinuje to, gdzie ma zostać przeniesiony kursor komórki po naciśnięciu klawisza Tab or Shift-Tab.
534536- **ExtendedColSizing.** Jeśli ma wartość True, użytkownik może zmienić rozmiar kolumn nie tylko w nagłówkach, ale wzdłuż ich wysokości.
535537
536538Inne właściwości, które również wpływają na wygląd siatek.
537539
538540**Options**.
539541
540542
541543Wł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.
542544
543545- **goFixedVertLine, goFixedHorzLine** Rysuje pionową lub poziomą linię, odpowiednio oddzielającą komórki lub kolumny w obszarze stałych komórek, domyślnie aktywne.
544546- **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.
545547- **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).
546548- **goRowSelect** Wybierz do zaznaczania cały wiersz zamiast pojedynczych komórek.
547549- **goFixedRowNumbering** Jeśli ustawione, siatka wykona automatyczną numerację wierszy w pierwszej stałej kolumnie.
548550- **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.
549551- **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.
550552
551553(dopisz więcej)
552554
553555### Opis procesu rysowania siatki
554556
555557Podobnie 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.
556558
557559Proces ten wygląda następująco:
558560
559561- 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.
560562- 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.
561563- 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:
562564 - *gdSelected* Komórka będzie miała wygląd wybranej, zaznaczonej.
563565 - *gdFocused* Komórka będzie miała wygląd skupionej (focus).
564566 - *gdFixed* Komórka musi być pomalowana jak komórka stała.
565567 - *gdHot* Mysz jest nad tą komórką, więc pomaluj ją z bieżącym podświetleniem
566568 - *gdPushed* Komórka jest klikana, więc pomaluj ją jako wciśniętą
567569
568570- **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:
569571- **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.
570572- **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?...
571573- **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.
572574- **Text.** W tym momencie (tylko dla TStringGrid), jeśli właściwość DefaultDrawing ma wartość True, malowana jest zawartość tekstowa komórki.
573575- **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).
574576- **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.
575577
576578#### Różnice w porównaniu z Delphi
577579
578580- W Lazarusie metoda TCustomGrid.DrawCell nie jest abstrakcyjna i jej domyślna implementacja wykonuje podstawowe wypełnianie tła komórki.
579581- W Delphi tekst komórki jest rysowany przed wejściem do zdarzenia OnDrawCell (patrz [raport o błędzie \#9619](http://www.freepascal.org/mantis/view.php?id=9619)).
580582
581583### Wybór komórki w siatce
582584
583585Lokalizację 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ć.
584586
585587Siatka 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.
586588
587589Gdy 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.
588590
589591Nastę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).
590592
591593Należ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.
592594
593595#### Różnice w porównaniu z Delphi
594596
595597- 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.
596598
597599### Gdy powyższe dostosowanie nie wystarczy, siatki pochodne
598600
599601Siatki pochodne zazwyczaj muszą zastąpić następujące metody:\
600602DrawAllRows: Rysuje wszystkie widoczne wiersze.\
601603DrawRow: Rysuje wszystkie komórki w rzędzie.\
602604DrawRow 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.\
603605DrawCell:\
604606DrawCellGrid:\
605607DrawCellText:\
606608DrawFocusRect:\
607609(napisz do mnie).\
608610
609611### Co dzieje się w metodzie `TCustomGrid.Paint`?
610612
611613Poniż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`.
612614
613615- **`DrawEdges`**: Rysuje zewnętrzną granicę siatki.
614616- **`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).
615617 - **`DrawRow`** (virtual): Jest wywoływana dla każdego wiersza wewnątrz obecnego widoku.
616618 - **`DrawCell`** (virtual): Jest najpierw wywoływana dla każdej „normalnej” (tj. niestałej) komórki w rzędzie.
617619 - **`PrepareCanvas`** (virtual): Ustawia style rysowania na płótnie zgodnie z wizualnymi właściwościami bieżącej komórki.
618620 - **`DrawFillRect`**: Rysuje tło komórki ze stylami ustawionymi w `PrepareCanvas`.
619621 - **`DrawCellGrid`** (virtual): Rysuje linie obramowania komórki.
620622 - **`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.
621623 - **`DrawCell`** (virtual): (patrz powyżej) Jest wywoływana dla każdej stałej (fixed) komórki w widocznym obszarze wiersza.
622624- **`DrawColRowMoving`**: Aktywna tylko podczas przenoszenia kolumny lub wiersza. Ta metoda rysuje linię wskazującą nową pozycję wiersza/kolumny.
623625- **`DrawBorder`**: W razie potrzeby (`Flat=TRUE` i `BorderStyle=bsSingle`) rysuje wewnętrzną linię obramowania.
624626
625627#### Dodatkowe metody rysowania w `TCustomGrid`
626628
627629Te 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.
628630
629631- **`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`).
630632- **`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`.
631633- **`DrawColumnText`** (virtual): Jest używany tylko dla komórek nagłówka kolumny.
632634 - **`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.
633635 - **`DrawCellText`** : (patrz wyżej)
634636- **`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).
635637
636638#### Metody rysowania wprowadzone przez `TCustomDrawGrid`
637639
638640Jak 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:
639641
640642- **`DrawCell`** (override):
641643 - **`PrepareCanvas`**: wywołuje odziedziczoną metodę z **`TCustomGrid`**.
642644 - **`DefaultDrawCell`** (virtual): Ta metoda jest wywoływana tylko wtedy, gdy procedura obsługi zdarzeń dla `OnDrawCell` NIE jest przypisana.
643645 - **`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`.
644646 - **`DrawCellAutonumbering`** (virtual): Kiedy `goFixedAutonumbering` jest włączona w `Options`, to numery wierszy są rysowane w pierwszej ustalonej kolumnie przy użyciu `TCustomGrid.DrawCellText`.
645647 - **`DrawColumnText`** (z `TCustomGrid`): Jest wywoływana tylko dla komórek nagłówka kolumny (zobacz *Dodatkowe metody rysowania w `TCustomGrid`*).
646648 - **`DrawTextInCell`** (z `TCustomGrid`): Jest wywoływana tylko dla 'normalnych' (tj. niestałych) komórek (zobacz *Dodatkowe metody rysowania w `TCustomGrid`*).
647649 - **`DrawCellGrid`** (virtual): Rysuje obramowanie komórki.
648650
649651### Zapisz i Odzyskaj zawartość siatki
650652
651653Metody **SaveToFile** i **LoadFromFile** umożliwiają siatce zapisywanie i pobieranie układu i danych do/z pliku w formacie XML. TStringGrid, odziedziczony z TCustomStringGrid, ma również możliwość „eksportowania” i „importowania” swojej zawartości do/z pliku w formacie wartości oddzielonych przecinkami, lepiej znanego jako format pliku CSV. Jest to opisane w dokumentacji do metod **SaveToCSVFile** i **LoadFromCSVFile** (do zrobienia: utworzyć łącza).
652654
653655Rodzaj informacji, które można zapisać, a następnie pobrać podczas używania **SaveToFile** i **LoadFromFile**, jest określony przez właściwość SaveOptions (typu TSaveOptions), która jest zestawem opcji opisanych w następujący sposób:
654656
655-`soDesign:     Zapisz i wczytaj ColCount,RowCount,FixedCols,FixedRows,`\
656-`              ColWidths, RowHeights i Options (TCustomGrid)`\
657-`soPosition:   Zapisz i wczytaj wartości pozycji Scroll, Row, Col i Selection (TCustomGrid)`\
658-`soAttributes: Zapisz i wczytaj kolory, wyrównanie tekstu i układ itp. (TCustomDrawGrid)`\
659-`soContent:    Zapisz i wczytaj tekst (TCustomStringGrid)`\
660-`soAll:        Ustaw wszystkie opcje (soAll:=[soDesign,soPosition,soAttributes,soContent];)`
657+``` pascal
658+soDesign: Zapisz i wczytaj ColCount,RowCount,FixedCols,FixedRows,
659+ ColWidths, RowHeights i Options (TCustomGrid)
660+soPosition: Zapisz i wczytaj wartości pozycji Scroll, Row, Col i Selection (TCustomGrid)
661+soAttributes: Zapisz i wczytaj kolory, wyrównanie tekstu i układ itp. (TCustomDrawGrid)
662+soContent: Zapisz i wczytaj tekst (TCustomStringGrid)
663+soAll: Ustaw wszystkie opcje (soAll:=[soDesign,soPosition,soAttributes,soContent];)
664+```
661665
662666Nie wszystkie opcje mają zastosowanie do wszystkich rodzajów siatek, na przykład soContent nie mają zastosowania do siatek pochodnych TCustomGrid, takich jak TDrawGrid, ponieważ ten rodzaj siatki nie zawiera pojęcia „treści”. TStringGrid jest specjalnym rodzajem siatki, która „wie”, jak obsługiwać łańcuchy i może użyć opcji soContent, jeśli jest określona.
663667
664668Opcja soAttributes nie jest używana w standardowych siatkach Lazarusa, jest dostępna w przypadku siatek potomnych.
665669
666670Podczas używania **LoadFromFile** siatka używa również właściwości SaveOptions, aby wiedzieć, jakie informacje należy pobrać z pliku, więc np. jest całkowicie możliwe określenie SaveOptions:=\[soDesign,soContent\] przy zapisywaniu i tylko SaveOptions :=\[soContent\] podczas ładowania.
667671
668672Dla TStringGrid domyślną wartością SaveOptions jest \[soContent\], dla innego rodzaju siatek SaveOptions jest pustym zbiorem.
669673
670674**Uwaga:** Jeden typowy problem podczas zapisywania i pobierania danych siatki występuje, gdy użytkownik określi właściwość SaveOptions przed **SaveToFile**, ale nie przed **LoadFromFile**. W przypadku użycia **LoadFromFile** jakiś czas po użyciu **SaveToFile** właściwość SaveOptions jest ustawiona prawidłowo, ale jeśli **LoadFromFile** zostanie wykonane przy następnym uruchomieniu programu, właściwość SaveOptions może nie zostać poprawnie skonfigurowane, z tego powodu zaleca się, aby zawsze określać właściwość SaveOptions tuż przed **LoadFromFile** lub robić to globalnie podczas uruchamiania programu, jak w poniższym przykładzie:
671675
672676------------------------------------------------------------------------
673677
674678**Przykład:**
675679
6766801. Najpierw przejdź do menu "Plik -\> Nowy -\> Aplikacja";
6776812. Umieść pusty TStringGrid w formularzu;
6786823. Umieść na formularzu TButton i TOpenDialog;
6796834. Dodaj zdarzenie OnCreate do formularza;
6806845. Dodaj zdarzenie OnClick dla przycisku.
681685
682686``` pascal
683687unit Unit1;
684688
685689{$mode objfpc}{$H+}
686690
687691interface
688692
689693uses
690694 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids,
691695 Buttons, StdCtrls, XMLCfg;
692696
693697type
694698
695699 { TForm1 }
696700 TForm1 = class(TForm)
697701 StringGrid1: TStringGrid;
698702 Button1: TButton;
699703 OpenDialog1: TOpenDialog;
700704 procedure Button1Click(Sender: TObject);
701705 procedure Form1Create(Sender: TObject);
702706 private
703707 { private declarations }
704708 public
705709 { public declarations }
706710 end;
707711
708712var
709713 Form1: TForm1;
710714
711715implementation
712716
713717{ TForm1 }
714718
715719procedure TForm1.Form1Create(Sender: TObject);
716720begin
717721 //ustawia SaveOptions w momencie tworzenia formularza
718722 stringgrid1.SaveOptions := [soDesign,soPosition,soAttributes,soContent];
719723end;
720724
721725procedure TForm1.Button1Click(Sender: TObject);
722726begin
723727 //Pytaj, czy uruchomiono metodę Execute w OpenDialog,
724728 //a gdy to nastąpi, użytkownik wybiera plik XML do załadowania,
725729 //którego nazwa była przechowywana we właściwości FileName.
726730
727731 if opendialog1.Execute then
728732 begin
729733 //Wyczyść siatkę
730734 StringGrid1.Clear;
731735 //Załaduj plik XML
732736 StringGrid1.LoadFromFile(OpenDialog1.FileName);
733737 //Odśwież siatkę
734738 StringGrid1.Refresh;
735739 end;
736740end;
737741
738742initialization
739743 {$I unit1.lrs}
740744
741745end.
742746```
743747
744748------------------------------------------------------------------------
745749
746750**Przykładowy plik xml:** (Skopiuj poniższy tekst do pliku txt. Nie zapomnij umieścić nagłówka xml :-))
747751
748752``` xml
749753<?xml version="1.0"?>
750754<CONFIG>
751755 <grid version="3">
752756 <saveoptions create="True" position="True" content="True"/>
753757 <design columncount="2" rowcount="5" fixedcols="1" fixedrows="1" defaultcolwidth="64" defaultRowHeight="20">
754758 <options>
755759 <goFixedVertLine value="True"/>
756760 <goFixedHorzLine value="True"/>
757761 <goVertLine value="True"/>
758762 <goHorzLine value="True"/>
759763 <goRangeSelect value="True"/>
760764 <goDrawFocusSelected value="False"/>
761765 <goRowSizing value="False"/>
762766 <goColSizing value="False"/>
763767 <goRowMoving value="False"/>
764768 <goColMoving value="False"/>
765769 <goEditing value="False"/>
766770 <goTabs value="False"/>
767771 <goRowSelect value="False"/>
768772 <goAlwaysShowEditor value="False"/>
769773 <goThumbTracking value="False"/>
770774 <goColSpanning value="False"/>
771775 <goRelaxedRowSelect value="False"/>
772776 <goDblClickAutoSize value="False"/>
773777 <goSmoothScroll value="True"/>
774778 </options>
775779 </design>
776780 <position topleftcol="1" topleftrow="1" col="1" row="1">
777781 <selection left="1" top="1" right="1" bottom="1"/>
778782 </position>
779783 <content>
780784 <cells cellcount="10">
781785 <cell1 column="0" row="0" text="Title Col1"/>
782786 <cell2 column="0" row="1" text="value(1.1)"/>
783787 <cell3 column="0" row="2" text="value(2.1)"/>
784788 <cell4 column="0" row="3" text="value(3.1)"/>
785789 <cell5 column="0" row="4" text="value(4.1)"/>
786790 <cell6 column="1" row="0" text="Title Col2"/>
787791 <cell7 column="1" row="1" text="value(1.2)"/>
788792 <cell8 column="1" row="2" text="value(2.2)"/>
789793 <cell9 column="1" row="3" text="value(3.2)"/>
790794 <cell10 column="1" row="4" text="value(4.2)"/>
791795 </cells>
792796 </content>
793797 </grid>
794798</CONFIG>
795799```
796800
797801### Edytory komórek siatki
798802
799803Siatka używa edytorów komórek do zmiany zawartości komórek.
800804
801805W przypadku wyspecjalizowanej siatki, takiej jak TStringGrid, edytor jest zwykłą jednowierszową kontrolką edytora tekstu, ale czasami pożądane jest posiadanie innych sposobów wprowadzania informacji. Na przykład:
802806
8038071. pokaż okno dialogowe otwierania pliku, po to by znaleźć lokalizację pliku, żeby użytkownik nie musiał ręcznie wpisywać pełnej ścieżki
8048082. jeśli tekst w komórce reprezentuje datę, wyświetl kalendarz, abyśmy mogli łatwo wybrać konkretną datę.
805809
806810Czasami informacje, które użytkownik powinien wprowadzić w komórce, są ograniczone do ograniczonej listy słów; w takim przypadku bezpośrednie wpisywanie informacji może wprowadzać błędy i może zaistnieć potrzeba zaimplementowania procedur sprawdzania poprawności. Możemy tego uniknąć, używając edytora komórek, który przedstawia użytkownikowi listę zawierającą tylko prawidłowe wartości.
807811
808812Dotyczy to również ogólnych siatek, takich jak TDrawGrid, w których użytkownik potrzebuje jakiejś struktury do przechowywania danych, które będą wyświetlane w siatce. W takiej sytuacji informacje wprowadzone w edytorze komórek aktualizują wewnętrzną strukturę, aby odzwierciedlić zmiany w siatce.
809813
810814#### Wbudowane edytory komórek
811815
812816Moduł grids.pas zawiera już niektóre z najczęściej używanych edytorów komórek gotowych do użycia w siatkach. Możliwe jest również tworzenie nowych edytorów komórek (niestandardowe edytory komórek), jeśli wbudowane edytory nie są odpowiednie do określonego zadania.
813817
814818Wbudowane edytory komórek to Button, Edit i Picklist.
815819
816820#### Korzystanie z edytorów komórek
817821
818822Użytkownicy mogą określić, jaki edytor będzie używany dla danej komórki, korzystając z jednej z dwóch metod.
819823
8208241. **Korzystanie z niestandardowej kolumny i wybranie właściwości ButtonStyle kolumny**. W pierwszej metodzie użytkownik może wybrać styl edytora, który będzie wyświetlany. Dostępne wartości to: cbsAuto, cbsEllipsis, cbsNone, cbsPickList, cbsCheckboxColumn, cbsButtonColumn.
8218252. **Używanie zdarzenia siatki OnSelectEditor**. W drugiej metodzie, w parametrze Editor użytkownik określa, którego edytora użyć dla komórki zidentyfikowanej dla kolumny aCol i wiersza ARow w siatce pochodnej TCustomDrawGrid lub TColumn w TCustomDBGrid. Do tego celu służy publiczna funkcja siatek EditorByStyle(), która jako parametr przyjmuje jedną z następujących wartości: cbsAuto, cbsEllipsis, cbsNone, cbsPickList, cbsCheckboxColumn, cbsButtonColumn. Ta metoda ma pierwszeństwo przed metodą pierwszą, gdy używane są kolumny niestandardowe. W tym miejscu można określić niestandardowy edytor komórek (patrz rozdział 5 [tego dokumentu](http://www.freepascal.org/~michael/articles/grids/grids.pdf) autorstwa Michaëla Van Canneyta, który wyjaśnia jak poprawnie zaimplementować niestandardowy edytor). To zdarzenie jest również miejscem do zamontowania edytora z wartościami specyficznymi dla komórki, wiersza lub kolumny (np. niestandardowe menu kontekstowe dla edytora komórek).
822826
823827Ustawienie właściwości *ButtonStyle* działa tylko wtedy, gdy kolumna jest tworzona za pomocą polecenia *StringGrid1.Columns.Add;*. Użycie wyrażenia takiego jak *StringGrid1.ColCount:=X;* spowoduje wyjątek. Ustawienie właściwości ButtonStyle można wykonać za pomocą podobnego kodu:
824828
825829``` pascal
826830if ColCB< StringGrid1.Columns.Count
827831 then StringGrid1.Columns.Items[ColCB].ButtonStyle:=cbsCheckboxColumn;
828832```
829833
830834#### Opis stylów edytora
831835
832836Poniżej znajduje się opis stylów edytora. Są to wartości wyliczeniowe typu TColumnButtonStyle, dlatego są poprzedzone przedrostkiem „cbs”. Ten typ został użyty, aby zachować kompatybilność z DBGrid firmy Delphi.
833837
834838- **cbsAuto**
835839
836840
837841To jest domyślny styl edytora dla siatek potomnych TCustomGrid. Rzeczywista klasa edytora, która będzie używana do edycji zawartości komórki, zależy od kilku czynników. W przypadku TCustomGrids używana jest klasa TStringCellEditor pochodząca z TCustomMaskEdit. Ten edytor wyspecjalizowany jest do edycji jednowierszowych ciągów string. Jest on następnie domyślnie używany w TStringGrid i TDrawGrid. W przypadku korzystania z kolumn niestandardowych, jeśli programista wypełnił właściwość PickList kolumny, działa to tak, jakby ustawiono styl edytora cbsPickList. W przypadku TCustomDBGrid, który ma pole typu boolean, zachowuje się on tak, jakby określono styl edytora cbsCheckBoxColumn. Jest to zalecana wartość dla niestandardowych edytorów komórek. Do zrobienia: odniesienie do OnEditingDone.
838842
839843- **cbsEllipsis**
840844
841845
842846Ten styl edytora jest najbardziej ogólny. Gdy jest używany, w komórce edycji pojawia się przycisk, a programiści mogą użyć zdarzenia siatki OnEditButtonClick, aby wykryć, kiedy użytkownik nacisnął przycisk i podjąć dowolną akcję zaprogramowaną dla takiej komórki. Na przykład programista może użyć tego stylu edytora, aby wyświetlić okno dialogowe kalendarza, aby umożliwić użytkownikowi łatwe wybranie określonej daty. Innymi możliwościami może być wyświetlenie okna dialogowego otwierania pliku w celu znalezienia plików, kalkulatora, aby użytkownik mógł wprowadzić liczbowy wynik obliczeń itp.
843847
844848
845849OnEditButtonClick to tylko powiadomienie, aby dowiedzieć się, w której komórce został kliknięty przycisk, sprawdź właściwości grid.Row i grid.Col.
846850
847851
848852A DBGrid ma specyficzne właściwości do pobierania aktywnej kolumny lub pola, a ponieważ to zdarzenie występuje w aktywnym rekordzie, może aktualizować informacje w aktywnym polu.
849853
850854
851855Ten styl edytora jest zaimplementowany przy użyciu TButtonCellEditor, bezpośredniego potomka TButton.
852856
853857- **cbsNone**
854858
855859
856860Ten styl edytora instruuje siatkę, aby nie używała żadnego edytora dla określonej komórki lub kolumny; zachowuje się wtedy tak, jakby siatka była tylko do odczytu dla takiej komórki lub kolumny.
857861
858862- **cbsPickList**
859863
860864
861865Służy do przedstawienia użytkownikowi listy wartości, które można wprowadzić. Ten styl edytora jest zaimplementowany przy użyciu TPickListCellEditor, komponentu wywodzącego się z TCustomComboBox. Lista wyświetlanych wartości jest wypełniana na jeden z dwóch sposobów, w zależności od metody użytej do wyboru stylu edytora.
862866
8638671. W przypadku używania kolumn niestandardowych programiści mogą wprowadzić listę wartości za pomocą właściwości PickList kolumny. \[DLA POCZĄTKUJĄCYCH: TODO: dokładna procedura edycji listy\]
8648682. W OnSelectEditor programiści pobierają instancję TPickListCellEditor za pomocą funkcji EditorByStyle(cbsPickList). Zobacz tutaj przykład
865869
866870Wartość w siatce TStringGrid automatycznie odzwierciedla wybraną wartość. W razie potrzeby programista może wykryć moment wybrania wartości, zapisując procedurę obsługi zdarzenia dla zdarzenia OnPickListSelect siatki, dzięki czemu można podjąć dodatkowe kroki (na przykład w celu przetworzenia nowej wartości). TODO: powiązanie z OnEditingDone.
867871
868872- **cbsCheckboxColumn**
869873
870874
871875Może to być przydatne, gdy zawartość danych powiązana z kolumną jest ograniczona do pary wartości, na przykład tak-nie, prawda-fałsz, włącz-wyłącz, 1-0 itp. Zamiast zmuszać użytkownika do wpisania wartości dla tego rodzaju danych w StringCellEditor lub aby wybrać jedną wartość z listy, cbsCheckboxColumn służy do modyfikowania danych kolumny za pomocą reprezentacji pola wyboru, którą użytkownik może przełączać za pomocą kliknięcia myszą lub wciskając klawisz spacji (jeśli kolumna zawierająca pole wyboru jest zaznaczona i jeśli StringGrid jest edytowalny).
872876
873877Pobieranie lub ustawianie wartości pola wyboru w komórce odbywa się w następujący sposób:
874878
875879``` pascal
876880StringGrid1.Cell[x,y]:='Z';
877881```
878882
879883
880884gdzie Z należy zastąpić przez *0* dla niezaznaczonego, *1* dla zaznaczonego i pusty ciąg dla wyszarzonego. Zauważ, że każda wartość (string) inna niż *0* i *1* będzie wyświetlana jako szare pole wyboru.
881885
882886
883887Jeśli właściwość ButtonStyle kolumny jest ustawiona na cbsAuto, a DBGrid wykryje, że pole powiązane z kolumną jest polem logicznym, wówczas siatka automatycznie użyje tego stylu edytora. Ten automatyczny wybór można wyłączyć lub włączyć za pomocą właściwości OptionsExtra DBGrid; ustawienie elementu dgeCheckboxColumn na wartość False wyłącza tą funkcję.
884888
885889
886890Wartości używane do rozpoznawania stanów zaznaczonych lub niezaznaczonych są ustawiane we właściwościach kolumny ValueChecked i ValueUnchecked.
887891
888892
889893W dowolnym momencie wartość pola może mieć od jednego do trzech stanów: Unchecked (niezaznaczone), Checked (zaznaczone) lub Grayed (wyszarzone). Wewnętrznie te stany są identyfikowane przez następujące wartości typu TDBGridCheckBoxState: gcbpUnChecked, gcbpChecked i gcbpGrayed.
890894
891895
892896Ten styl edytora nie używa prawdziwych komponentów TCheckbox do obsługi interakcji użytkownika: wizualną reprezentację zapewniają trzy wbudowane obrazy bitmapowe, które odpowiadają możliwym stanom pola wyboru. Użyte mapy bitowe można dostosować, pisząc procedurę obsługi zdarzenia DBGrid OnUserCheckboxBitmap; program obsługi tego zdarzenia otrzymuje stan pola wyboru w parametrze CheckedState typu TDBGridCheckboxState oraz parametr mapy bitowej, którego programista może użyć do określenia niestandardowych map bitowych.
893897
894898- **cbsButtonColumn**
895899
896900
897901Ten styl edytora służy do wyświetlania przycisku w każdej komórce w kolumnie. Podobnie jak w przypadku cbsCheckboxColumn ten edytor nie używa prawdziwych przycisków, wygląd jest określony przez aktualny motyw zestawu widżetów.
898902
899903
900904Użytkownik wie, jaki konkretny przycisk został naciśnięty, obsługując OnEditButtonClick w siatce i sprawdzając kolumnę i wiersz siatki. Zauważ, że w tym konkretnym przypadku zmienne col i row siatki nie identyfikują aktualnie zaznaczonej komórki, ale komórkę klikniętego przycisku. Po obsłużeniu zdarzenia OnEditButtonClick i jeśli użytkownik nie zmodyfikował col lub row siatki w tej procedurze obsługi, siatka automatycznie resetuje col i row, aby odzwierciedlić aktualnie wybraną komórkę. Podczas obsługi OnEditButtonClick bieżący wybór siatki jest dostępny w grid.Selection, który jest właściwością typu TRect, Left i Right reprezentują indeksy kolumn, Top i Bottom są indeksami wierszy.
901905
902906
903907Podpis przycisku to odpowiedni ciąg string komórki.
904908
905909### Edycja siatek
906910
907911Efekt edycji jest różny w zależności od rodzaju użytej siatki, na przykład TStringGrid przechowuje edytowany tekst wewnętrznie, a TDBGrid wpływa na rekordy w zestawie danych (dataset). TDrawGrid nie wie, co zrobić z edytowanym tekstem, jeśli programista nie przejmie nad nim kontroli, jest on po prostu odrzucany.\
908912Dla TDrawGrid (chociaż powinno to działać dla wszystkich klas siatki) w celu uzyskania dostępu do edytowanego tekstu, programista może użyć zdarzenia **OnSetEditText**, które jest wyzwalane za każdym razem, gdy użytkownik zmodyfikuje coś w edytorze, parametry *aCol* i *aRow* tego zdarzenia identyfikują edytowaną komórkę, parametr *Value* przechowuje tekst, jest to zalecana metoda. Innym sposobem dostępu do edytowanego tekstu jest pobranie go bezpośrednio z edytora po zakończeniu procesu edycji za pomocą zdarzenia **OnEditingDone**. Można to osiągnąć, uzyskując dostęp do wewnętrznego edytora używanego do edycji, w tym przypadku domyślnego „String Cell Editor” (Komórkowy Edytor String). W tym celu istnieją dwie metody: Pierwsza polega na użyciu zdarzenia **OnSelectEditor**, gdzie parametr *Editor* jest instancją, która będzie używana do edycji komórki, musisz zapisać tę instancję do zmiennej, na przykład TheEditor (typu *TSringCellEditor*), do późniejszego wykorzystania w **OnEditingDone**. Drugą alternatywą jest użycie metody siatki **EditorByStyle**, ta metoda akceptuje „styl edytora” jako parametr i zwraca instancję edytora odpowiadającego temu stylowi. W naszym przypadku wiedząc, że styl cbsAuto zwraca domyślny edytor komórek, w module obsługi zdarzenia **OnEditingDone** możemy bezpośrednio użyć TheEditor := Grid.EditorByStyle(cbsAuto). Następnie możesz pobrać tekst za pomocą *TheEditor.Text*. Jeśli zastosujesz tę metodę, zauważ, że „z wielką mocą wiąże się wielka odpowiedzialność”.
909913
910914#### Opcje i właściwości wpływające na edycję
911915
912916Zachowanie edycyjne jest kontrolowane przez szereg właściwości i opcji, praktycznie każde dostosowanie lub opcje, które wpływają na edycję, wymagają edytowalnej siatki, w przeciwnym razie takie dostosowanie może zostać zignorowane.\
913917Na początku edytowalny stan siatek jest inny, dla TDrawGrid i TStringGrid edycja jest wyłączona, dla TDbGrid jest domyślnie włączona.\
914918Właściwość **Options** zawiera kilka pozycji, które zajmują się edycją, są one opisane poniżej:\
915919***goEditing, dgEditing (w DbGrid)**. Ta opcja zmienia edytowalny stan siatki, można ją zmienić w czasie wykonywania, ponieważ jest zaznaczona, gdy edycja ma się rozpocząć.
916920
917921- **goAlwaysShowEditor**. Zwykle edytor jest ukryty i staje się widoczny tylko wtedy, gdy jest potrzebny. Dzięki tej opcji edytor będzie widoczny przez cały czas, jeśli siatka nie jest edytowalna, opcja ta jest ignorowana, a edytor jest zawsze ukryty.
918922
919923### Hint dla komórek
920924
921925„Hint” to właściwość wyświetlająca wskazówkę, krótką notatkę lub podpowiedź dla kontrolki, nad którą umieścimy kursor myszy. Inna nazwa tego elementu to „Tooltip”. Nazwy spotykane w języku polskim to także „dymek” lub „chmurka”.
922926
923927Oprócz standardowej właściwości Hint dostępnej dla większości kontrolek, potomkowie TCustomGrid mogą wyświetlać specjalny dymek dla komórki, nad którą znajduje się kursor myszy. Ta funkcja jest kontrolowana przez opcje siatki **goCellHints** i **goTruncCellHints** (lub **dgCellHints** i **gdTruncCellHints** odpowiednio dla DBGrid):
924928
925929- **goCellHints** aktywuje zdarzenie **OnGetCellHint** w celu pobrania wyświetlanego tekstu dymku dla komórki określonej przez przekazane parametry. W przypadku TDrawGrid i TStringGrid podane są indeksy kolumn i wierszy, natomiast w przypadku TDBGrid tekst komórki może zostać wydobyty z pola przypisanego do określonego obiektu kolumny.
926930- **goTruncCellHints** wyświetla dymek tylko wtedy, gdy tekst nie mieści się w komórce i jest obcięty; tekst podpowiedzi to nieobcięty tekst komórki. W Lazarusie 1.9+ ten tekst jest przekazywany do zdarzenia **OnGetCellHint** w celu dalszego doprecyzowania (np. wyświetlenie całego tekstu notatki w dymku). W przypadku skróconych tekstów komórek zaleca się również włączenie opcji **goCellEllipsis** (lub **dgCellEllipsis** dla DBGrid), która dodaje '...' do skróconego tekstu komórki.
927931
928932Jeśli siatka ma wartość w swojej standardowej właściwości **Hint**, wówczas właściwość **HintPriority** może być użyta do kontrolowania, w jaki sposób wszystkie te dymki mogą zostać połączone w jedno wyskakujące okienko:
929933
930934- **chpAll** umieszcza tekst z właściwości Hint w pierwszym wierszu, dymek określony przez zdarzenie OnGetCellHint w drugim wierszu, a wskazówkę dotyczącą obciętych komórek w trzecim wierszu
931935- **chpAllNoDefault** wyświetla tylko dymki dotyczące komórek podane przez zdarzenie OnGetCellHint i obcięte komórki.
932936- **chpTruncOnly** wyświetla tylko dymki dotyczące obciętych komórek; to są ustawienia domyślne.
933937
934938Ponadto standardowa właściwość siatki **ShowHint** musi być ustawiona na wartość True, aby wyświetlać dymki dotyczące komórek.
935939
936940## Grids w praktyce i przykłady
937941
938942### Skupienie komórki
939943
940944Wykonanie skupienia (focus) dla komórki w TStringGrid jest łatwe. Zwróć uwagę, że liczenie (zwykle w programowaniu) zaczyna się od zera, a nie od 1. Aby zrobić skupienie dla komórki w 10. rzędzie i 9. kolumnie, wykonaj:
941945
942946``` Pascal
943947StringGrid1.Row := 9;
944948StringGrid1.Col := 8;
945949```
946950
947951### Przykład: Jak ustawić niestandardowy edytor komórek
948952
949953Zobacz lazarus/examples/gridexamples/gridcelleditor/gridcelleditor.lpi (począwszy od Lazarusa 1.2)
950954
951955#### Przykład: Jak dodać edytor przycisków
952956
953957``` pascal
954958// Warunkowo pokaż edytor przycisków w kolumnie o indeksie 1 lub 2, jeśli
955959// komórka w kolumnie o indeksie 1 jest pusta
956960
957961procedure TForm1.StringGrid1SelectEditor(Sender: TObject; aCol, aRow: Integer;
958962 var Editor: TWinControl);
959963begin
960964 if (aCol = 1) or (aCol = 2) then
961965 if StringGrid1.Cells[1,aRow] = '' then
962966 begin
963967 Editor := StringGrid1.EditorByStyle(cbsEllipsis);
964968 end;
965969 end;
966970
967971// Uruchamianie akcji...
968972procedure TForm1.StringGrid1EditButtonClick(Sender: TObject);
969973begin
970974 if StringGrid1.Col = 1 then ShowMessage('kliknięto edytor kolumny 1');
971975 if StringGrid1.Col = 2 then ShowMessage('kliknięto edytor kolumny 2');
972976end;
973977```
974978
975979### Przykład: Praca z PickList, jak ustawić ją tylko do odczytu i jak wypełnić w czasie wykonywania
976980
977981Za pomocą zdarzenia OnSelectEditor w siatce można dostosować zachowanie edytora PickList (patrz styl przycisku cbsPickList). W kolejnym przykładzie edytor listy wyboru w kolumnie 1 został zmodyfikowany tak, że w nieparzystych wierszach użytkownik może wprowadzać wartości przez ręczne wpisanie, w parzystych wierszach wartości są ograniczone do tych zawartych na liście wyboru. Ten przykład pokazuje również, jak wypełnić listę różnymi wartościami w zależności od przetwarzanego wiersza.
978982
979983``` pascal
980984procedure TForm1.gridSelectEditor(Sender: TObject; aCol, aRow: Integer;
981985 var Editor: TWinControl);
982986begin
983987 if aCol=1 then begin
984988 if (Editor is TCustomComboBox) then
985989 with Editor as TCustomComboBox do begin
986990 if (aRow mod 2=0) then
987991 Style := csDropDown
988992 else
989993 Style := csDropDownList;
990994 case aRow of
991995 1:
992996 Items.CommaText := 'ONE,TWO,THREE,FOUR';
993997 2:
994998 Items.CommaText := 'A,B,C,D,E';
995999 3:
9961000 Items.CommaText := 'MX,ES,NL,UK';
9971001 4:
9981002 Items.CommaText := 'RED,GREEN,BLUE,YELLOW';
9991003 end;
10001004 end;
10011005 end;
10021006end;
10031007```
10041008
10051009### Wyrównywanie tekstu w StringGrids
10061010
10071011Ten kod pokazuje, jak używać różnych sposobów wyrównania tekstu w kolumnach 2 i 3.
10081012
10091013``` pascal
10101014procedure TForm1.StringGrid1PrepareCanvas(sender: TObject; aCol, aRow: Integer;
10111015 aState: TGridDrawState);
10121016var
10131017 MyTextStyle: TTextStyle;
10141018begin
10151019 if (aCol=2) or (aCol=3) then
10161020 begin
10171021 MyTextStyle := StringGrid1.Canvas.TextStyle;
10181022 if aCol=2 then
10191023 MyTextStyle.Alignment := taRightJustify
10201024 else
10211025 if aCol=3 then
10221026 MyTextStyle.Alignment := taCenter;
10231027 StringGrid1.Canvas.TextStyle := MyTextStyle;
10241028 end;
10251029end;
10261030```
10271031
10281032### Wielowierszowy tekst w siatkach
10291033
10301034Ten przykład pokazuje, jak utworzyć tekst wielowierszowy w komórce \[3,2\]. Działa to tak samo dla DBGrid, gdzie OnPrepareCanvas ma parametry do radzenia sobie z TColumns, a stamtąd z TFields.
10311035
10321036``` pascal
10331037procedure TForm1.StringGrid1PrepareCanvas(sender: TObject; aCol, aRow: Integer;
10341038 aState: TGridDrawState);
10351039var
10361040 MyTextStyle: TTextStyle;
10371041begin
10381042 if (aRow=2) or (aCol=3) then
10391043 begin
10401044 MyTextStyle := StringGrid1.Canvas.TextStyle;
10411045 MyTextStyle.SingleLine := false;
10421046 StringGrid1.Canvas.TextStyle := MyTextStyle;
10431047 end;
10441048end;
10451049```
10461050
10471051### Weryfikacja wprowadzonych wartości
10481052
10491053Lazarus w wersji 0.9.29 wprowadza w StringGrid zdarzenie OnValidateEntry typu TValidateEntryEvent, które ma następującą deklarację:
10501054
10511055``` pascal
10521056type
10531057 TValidateEntryEvent = procedure(sender: TObject; aCol, aRow: Integer; const OldValue: string; var NewValue: string) of object;
10541058```
10551059
1056-`aCol, aRow to współrzędne sprawdzanej komórki.`\
1057-`OldValue to wartość, która znajdowała się w komórce cells[aCol, aRow] przed rozpoczęciem edycji.`\
1058-`NewValue to wartość, która zostanie ostatecznie wstawiona do komórki cells[aCol, aRow].`
1060+```text
1061+aCol, aRow to współrzędne sprawdzanej komórki.
1062+OldValue to wartość, która znajdowała się w komórce cells[aCol, aRow] przed rozpoczęciem edycji.
1063+NewValue to wartość, która zostanie ostatecznie wstawiona do komórki cells[aCol, aRow].
1064+```
10591065
10601066Ze względu na sposób, w jaki działa StringGrid, ustawiając wartość komórki podczas edycji przez użytkownika (patrz zdarzenie OnSetEditText w siatce i metoda SetEditText), gdy wyzwalane jest zdarzenie OnValidateEntry, komórka zawiera już wprowadzoną wartość (prawidłową lub nie); za pomocą argumentów zdarzenia OldValue i NewValue wartość komórki może zostać zweryfikowana i zmieniona w razie potrzeby.
10611067
10621068Zwykle sprawdzanie poprawności następuje, gdy użytkownik przeniósł się do innej komórki. Jeśli walidacja się nie powiedzie, pożądane jest, aby edytor komórek był widoczny/aktywny, aby wpisana wartość mogła zostać poprawiona przez użytkownika. Aby siatka wiedziała, że ​​walidacja nie powiodła się, należy zgłosić wyjątek. Siatka obsłuży wyjątek poprzez Application.HandleException i każdy ruch zostanie anulowany.
10631069
10641070Na przykład, załóżmy że komórka cell\[1,1\] powinna zawierać tylko wartości 'A' lub 'B', walidację można przeprowadzić za pomocą:
10651071
10661072``` pascal
10671073procedure TForm1.GridValidateEntry(sender: TObject; aCol,
10681074 aRow: Integer; const OldValue: string; var NewValue: String);
10691075begin
10701076 if (aCol=1) and (aRow=1) then begin
10711077 if grid.Cells[aCol,aRow]<>'A') and grid.Cells[aCol,aRow]<>'B') then begin
10721078 // ustaw nową prawidłową wartość, aby użytkownik mógł na przykład nacisnąć RETURN, aby kontynuować.
10731079 NewValue := 'A';
10741080 // inną opcją jest powrót do poprzedniej wartości komórki (która z założenia jest prawidłowa)
10751081 // NewValue := OldValue;
10761082 // Użyj EAbort zamiast innego przerwania typu Exception, aby uniknąć okna dialogowego
10771083 // z fałszywym komunikatem błędu i odwrotnego debugowania
10781084 raise EAbort.Create('Tylko A lub B są tutaj dozwolone');
10791085 end else begin
10801086 // jeśli nie zostanie zgłoszony żaden wyjątek, przyjmuje się, że wartość jest prawidłowa, ale
10811087 // w razie potrzeby ostateczną wartość można jeszcze zmienić, wypełniając NewValue inną wartością
10821088
10831089 // komputer wie lepiej :)
10841090 if grid.Cells[1,1]='A' then
10851091 NewValue := 'B'
10861092 else
10871093 NewValue := 'A';
10881094 end;
10891095 end;
10901096end;
10911097```
10921098
10931099### Sortowanie kolumn lub wierszy
10941100
10951101Właściwość ColumnClickSorts umożliwia automatyczne sortowanie siatki wtedy, gdy użytkownik kliknie nagłówek kolumny. Wielokrotne kliknięcie tej samej kolumny zmienia kolejność sortowania. Wyświetlane są obrazy domyślnego sortowania kolumn, które wskazują, która kolumna została kliknięta.
10961102
10971103W kodzie możesz użyć metody SortColRow().
10981104
10991105Pierwszy parametr, IsColumn, to wartość logiczna. Ustaw ją na:
11001106
11011107- True jeśli posortowana ma być kolumna
11021108- False jeśli posortowany ma zostać wiersz.
11031109
11041110Drugi parametr, index, jest liczbą całkowitą:
11051111
11061112- Indeks wskazuje kolumnę lub wiersz do posortowania.
11071113
11081114Ostatnie dwa parametry są opcjonalne, określają podzakres wierszy lub kolumn do sortowania.
11091115
11101116- FromIndex (od kolumny lub wiersza)
11111117- ToIndex (do kolumny lub wiersza)
11121118
11131119Jeśli ostatnie dwa parametry nie zostaną określone, sortowana jest cała kolumna lub wiersz.
11141120
11151121Sortowanie wykorzystuje algorytm QuickSort, można go zmienić, jeśli siatka potomna przesłoni metodę sort() i wywoła funkcję doCompareCells w celu porównania komórek.
11161122
11171123Domyślnie zawartość komórek sortowana jest jako ciągi string w kolejności rosnącej lub malejącej. Kolejność można wybrać za pomocą właściwości SortOrder. Domyślnie używana jest kolejność rosnąca.
11181124
11191125``` pascal
11201126// Sortuj kolumnę 3 w kolejności rosnącej
11211127grid.SortColRow(true, 3);
11221128
11231129// Sortuj kolumnę 3 w kolejności malejącej, pomiń wiersze stałe (fixed) u góry
11241130grid.SortOrder := soDescending; // lub soAscending
11251131grid.SortColRow(true, 3, grid.FixedRows, grid.RowCount-1);
11261132```
11271133
11281134Do niestandardowego sortowania liczb, dat, stanów itp. StringGrid ma zdarzenie OnCompareCells, które użytkownicy mogą wykorzystać na przykład w ten sposób:
11291135
11301136``` pascal
11311137procedure TForm1.GridCompareCells(Sender: TObject; ACol, ARow, BCol, BRow: Integer; var Result: integer);
11321138begin
11331139 // Wynik będzie <0, =0 lub >0 dla normalnego sortowania.
11341140 result := StrToIntDef(Grid.Cells[ACol,ARow],0)-StrToIntDef(Grid.Cells[BCol,BRow],0);
11351141 //W przypadku odwrotnej kolejności, wystarczy zanegować wynik (np. bazując na SortOrder siatki).
11361142 if StringGrid1.SortOrder = soDescending then
11371143 result := -result;
11381144end;
11391145```
11401146
11411147Możesz użyć OnCompareCells również wtedy, gdy automatyczne sortowanie kolumn jest włączone za pomocą właściwości ColumnClickSorts.
11421148
11431149### Zastąp sortowanie automatyczne (ColumnClickSorts ustawione na False ). Unikaj niektórych kolumn. Pokaż strzałki sortowania w nagłówku kolumny
11441150
11451151(gdy ColumnClickSorts jest ustawione na False, to w nagłówku kolumny NIE są wyświetlane strzałki sortowania, a więc musimy ustawić strzałki.)
11461152
11471153``` pascal
11481154procedure TForm1.StringGrid1HeaderClick(Sender: TObject; IsColumn: Boolean;
11491155 Index: Integer);
11501156begin
11511157 if isColumn then with StringGrid1 do
11521158 begin
11531159 col:=Index; // Wybierz kolumnę do sortowania
11541160 if Tag = 0 then Tag :=-1 // Załóżmy, że dane w kolumnie są posortowane rosnąco
11551161 else Tag := Tag * -1; // Używanie StringGrid1.Tag do przechowywania porządku sortowania
11561162 // Pierwsze kliknięcie nagłówka posortuje kolumnę malejąco
11571163
11581164 // Aktywuj CompareCells (aktywuj sortowanie)
11591165 case Index of
11601166 0: col:=-1; // Nie sortuj kolumny 0 i nie pokazuj strzałki sortowania
11611167 1: SortColRow(True, Index); // Sortowanie odbędzie się w CompareCells zaraz po wykonaniu instrukcji
11621168 2: SortColRow(True, Index);
11631169 3: SortColRow(True, Index);
11641170 4: SortColRow(True, Index);
11651171 5: col:=-1; // Nie sortuj kolumny 5 i nie pokazuj strzałki sortowania
11661172 end;
11671173 end;
11681174end;
11691175
11701176// Compare zwraca jedną z następujących wartości:
11711177// jeśli A<B zwraca: -1 ( Rosnąco )
11721178// jeśli A=B zwraca: 0
11731179// jeśli A>B zwraca: 1 ( Malejąco)
11741180
11751181// Jak sortować: Text, Integer, Float, DateTime:
11761182
11771183procedure TForm1.StringGrid1CompareCells(Sender: TObject; ACol, ARow, BCol,
11781184 BRow: Integer; var Result: integer);
11791185
11801186 function CompareTextAsText: Integer; // Text
11811187 begin
11821188 CompareText(Cells[ACol,ARow], Cells[BCol,BRow]);
11831189 end;
11841190
11851191 function CompareTextAsInteger: Integer;
11861192 var i1,i2:Integer;
11871193 begin
11881194 if TryStrToInt(StringGrid1.Cells[ACol,ARow],i1) and // Integer
11891195 TryStrToInt(StringGrid1.Cells[BCol,BRow],i2) then
11901196 Result := CompareValue(i1, i2)
11911197 else Exit(0);
11921198 end;
11931199
11941200 function CompareTextAsFloat: Integer; // Float
11951201 var f1,f2:Extended;
11961202 begin
11971203 if TryStrToFloat(StringGrid1.Cells[ACol,ARow],f1) and
11981204 TryStrToFloat(StringGrid1.Cells[BCol,BRow],f2) then
11991205 Result := CompareValue(f1, f2)
12001206 else Exit(0);
12011207 end;
12021208
12031209 function CompareTextAsDateTime: Integer; // DateTime
12041210 var
12051211 D1, D2 : TDateTime;
12061212 begin
12071213 if Trim(StringGrid1.Cells[ACol,ARow]) <> Trim(StringGrid1.Cells[BCol,BRow]) then
12081214 begin
12091215 if trim(StringGrid1.Cells[ACol,ARow]) = '' then Exit(1);
12101216 if Trim(StringGrid1.Cells[BCol,BRow]) = '' then Exit(-1);
12111217 end
12121218 else Exit(0);
12131219
12141220 if TryStrToDate(StringGrid1.Cells[ACol,ARow], D1, 'yy/mm/dd') and
12151221 TryStrToDate(StringGrid1.Cells[BCol,BRow], D2, 'yy/mm/dd') then
12161222 Result := CompareDateTime(D1, D2)
12171223 else Exit(0);
12181224 end;
12191225
12201226begin // Nie rób tutaj nic więcej, sortowanie może być zrobione niepoprawnie
12211227 With StringGrid1 do
12221228 begin
12231229 case ACol of
12241230 0 : ; // Nie sortuj kolumny 0
12251231 1 : Result := CompareTextAsText; // Text
12261232 2 : Result := CompareTextAsInteger; // Integer
12271233 3 : Result := CompareTextAsFloat; // Float
12281234 4 : Result := CompareTextAsDateTime; // DateTime
12291235 end; {Case}
12301236 end;
12311237 if StringGrid1.Tag = -1 then Result := -Result; // Zmień kolejność sortowania
12321238end;
12331239
12341240// DrawCell załatwia sprawę, poprzednie obrazy strzałek są usuwane:
12351241procedure TForm1.StringGrid1DrawCell(Sender: TObject; aCol, aRow: Integer;
12361242 aRect: TRect; aState: TGridDrawState);
12371243
12381244 procedure DrawArrow(ImgIndex:Integer); // Potrzebujesz obrazów strzałek w górę/w dół w ImageList
12391245 begin
12401246 with StringGrid1 do
12411247 TitleImageList.Draw(Canvas, // TitleImageList z StringGrid
12421248 ARect.Right - TitleImageList.Width,
12431249 (ARect.Bottom - ARect.Top - TitleImageList.Height) div 2 + 2, // Położenie strzałki można regulować.
12441250 ImgIndex );
12451251 end;
12461252begin
12471253 if Col > 0 then // W tym demo nie ma strzałek w kolumnie 0
12481254 if (ARow = 0) and // Załóżmy, że wiersz 0 jest wierszem tytułu
12491255 Assigned(TitleImageList) then // Potrzebujesz strzałek w górę/w dół w ImageList
12501256 case Columns.Items[aCol].Tag of // Użyj właściwości Tag kolumny jako indeksu strzałki rosnąco/malejąco
12511257 -1: DrawArrow(1); // Zastąp swoim indeksem strzałki w dół
12521258 0: DrawArrow(-1); // Usuń poprzedni obraz
12531259 1: DrawArrow(2); // Zastąp swoim indeksem strzałki w górę
12541260 end;
12551261end;
12561262```
12571263
12581264### Podświetlenie wybranych komórek kolumny i wiersza
12591265
12601266W rewizji 40276 Lazarusa dodano opcję (**gdRowHighlight**), która działa podobnie do **goRowSelect**, ale używa jaśniejszego koloru do zaznaczania, a prostokąt skupienia wskazuje zaznaczoną komórką, a nie cały rząd. Działa to dobrze w przypadku wierszy, ale co z kolumnami?.
12611267
12621268Ta sekcja przedstawia sposób podświetlania kolumn, wierszy lub obu (przykład podświetlający tylko nagłówki kolumn i wierszy można znaleźć w lazarus/examples/gridexamples/spreadsheet, ten praktyczny poradnik jest tak naprawdę rozszerzeniem tego przykładu). Wykorzystywane są dwa zdarzenia siatki: **OnBeforeSelection** i **OnPrepareCanvas**, a rysowanie nie jest konieczne.
12631269
12641270Zdarzenie **OnBeforeSelection** jest wyzwalane, gdy zaznaczenie ma ulec zmianie. W tym zdarzeniu możemy się dowiedzieć, która komórka jest aktualnie zaznaczona i jaka komórka zostanie wybrana jako następna. Używamy tych informacji, aby unieważnić cały wiersz lub kolumnę zarówno dla starych, jak i nowych komórek. Gdy rozpocznie się następny cykl malowania, siatka zostanie poinstruowana, aby pomalować komórki należące do obszarów unieważnionych. Jednym z pierwszych kroków podczas malowania jest wywołanie zdarzenia **OnPrepareCanvas** (jeśli istnieje) w celu ustawienia domyślnych właściwości płótna. Używamy tego zdarzenia do ustawienia podświetlonego wiersza lub kolumny:
12651271
12661272``` pascal
12671273procedure TForm1.gridBeforeSelection(Sender: TObject; aCol, aRow: Integer);
12681274begin
12691275 // tutaj możemy zdecydować, czy chcemy podświetlać kolumny, wiersze, czy jedno i drugie
12701276 // w tym przykładzie podświetlamy oba
12711277
12721278 if Grid.Col<>aCol then
12731279 begin
12741280 // wykryto zmianę w bieżącej kolumnie
12751281 grid.InvalidateCol(aCol); // unieważnia nową wybraną kolumnę komórek
12761282 grid.InvalidateCol(grid.Col); // unieważnia bieżącą (będzie to „stara”) wybrana kolumna
12771283 end;
12781284 if Grid.Row<>aRow then
12791285 begin
12801286 grid.InvalidateRow(aRow); // unieważnia nowy wybrany wiersz komórki
12811287 grid.InvalidateRow(grid.Row); // unieważnia bieżący (będzie to „stary”) wybrany wiersz
12821288 end;
12831289end;
12841290
12851291procedure TForm1.gridPrepareCanvas(sender: TObject; aCol, aRow: Integer;
12861292 aState: TGridDrawState);
12871293begin
12881294 if gdFixed in aState then
12891295 begin
12901296 if (aCol=grid.Col) or (aRow=grid.Row) then
12911297 grid.Canvas.Brush.Color := clInactiveCaption; // podświetliłoby to również nagłówki kolumn lub wierszy
12921298 end else
12931299 if gdFocused in aState then begin
12941300 // zostawiamy w spokoju aktualnie wybraną/skupioną komórkę
12951301 end else
12961302 if (aCol=Grid.Col) or (aRow=grid.Row) then
12971303 grid.Canvas.Brush.Color := clSkyBlue; // podświetl wiersze i kolumny kolorem clSkyBlue
12981304end;
12991305```
13001306
13011307### Unikanie pustego miejsca po prawej stronie ostatniej kolumny
13021308
13031309Aby to osiągnąć, siatka musi być w trybie kolumnowym. Gdy właściwość siatki `AutoFillColumns` ma wartość `True`, puste miejsce jest dzielone przez wszystkie kolumny, które mają niezerowy `SizePriority`. Dlatego powinieneś wykonać następujące kroki, aby wypełnić całą poziomą przestrzeń siatki:
13041310
13051311- Ustaw `AutoFillColumns` na `True`.
13061312- Korzystając z edytora kolumn, dodaj tyle kolumn, ile potrzebujesz.
13071313- Zaznacz każdą kolumnę w drzewie obiektów nad inspektorem obiektów i ustaw jej `SizePriority` na `0`.
13081314- Teraz zdecyduj, która kolumna zostanie poszerzona tak, że cała pusta przestrzeń zostanie wykorzystana. Ustaw `SizePriority` tej kolumny na `1`.
13091315
13101316### Jak przewijać siatkę w czasie rzeczywistym (przesuwanie paska przewijania za pomocą myszy)
13111317
13121318If you scroll a Grid by moving the scrollbar with the mouse then the Grid per default is not moved "in realtime". Only after you release the mouse, the Grid "jumps" to its new position. You can enable a scrolling in "realtime" by adding Option `goThumbTracking`.
13131319
13141320Example:
13151321
13161322``` pascal
13171323 StringGrid1.Options:=StringGrid1.Options + [goThumbTracking];
13181324```
13191325
13201326Unfortunately this Option is neither documented in `<lazarus-installdir>\lcl\grids.pas` (ver 2.0.6) nor in <https://lazarus-ccr.sourceforge.io/docs/lcl/grids/tgridoptions.html>
13211327
13221328Jeśli przewijasz siatkę, przesuwając pasek przewijania za pomocą myszy, domyślnie siatka nie jest przesuwana „w czasie rzeczywistym”. Dopiero po zwolnieniu myszy siatka „przeskakuje” do nowej pozycji. Możesz włączyć przewijanie w czasie rzeczywistym, dodając opcję `goThumbTracking`.
13231329
13241330Przykład:
13251331
13261332``` pascal
13271333 StringGrid1.Options:=StringGrid1.Options + [goThumbTracking];
13281334```
13291335
13301336Niestety ta opcja nie jest udokumentowana w `<lazarus-installdir>\lcl\grids.pas` (wersja 2.0.6) ani w <https://lazarus-ccr.sourceforge.io/docs/lcl/grids/tgridoptions.html>
13311337
13321338### Jak zmienić rozmiar wiersza na podstawie zawartości komórek?
13331339
13341340Lacak w raporcie o błędzie [\#38473](https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/38473) przedstawił następujący kod:
13351341
13361342``` pascal
13371343
13381344{ TStringGridHelper }
13391345 TStringGridHelper = class helper for TStringGrid
13401346 protected
13411347 procedure AutoSizeRow(aRow: integer);
13421348 end;
13431349
13441350{ TStringGridHelper }
13451351procedure TStringGridHelper.AutoSizeRow(aRow: integer);
13461352var
13471353 aCanvas: TCanvas;
13481354 aCol, maxRowHeight:integer;
13491355 aText: String;
13501356 textRect: TRect;
13511357begin
13521358 aCanvas := GetWorkingCanvas(Canvas);
13531359 maxRowHeight := DefaultRowHeight;
13541360 for aCol:=0 to ColCount-1 do begin
13551361 aText := Cells[aCol,aRow];
13561362 textRect := Rect(0, 0, ColWidths[aCol], MaxInt);
13571363 DrawText(aCanvas.Handle, PChar(aText), Length(aText), textRect, DT_CALCRECT or DT_WORDBREAK);
13581364 if maxRowHeight < textRect.Height then
13591365 maxRowHeight := textRect.Height
13601366 end;
13611367 if aCanvas<>Canvas then FreeWorkingCanvas(aCanvas);
13621368 RowHeights[aRow] := maxRowHeight+2;
13631369end;
13641370```
13651371
13661372Dodaj to gdzieś w swoim kodzie źródłowym, a następnie możesz zmieniać rozmiar wiersza tak, jakby procedura AutoSizeRow była częścią siatki, na przykład:
13671373
13681374 // Zmień rozmiar wiersza o indeksie 2
13691375 grid.AutoSizeRow(2);
13701376
13711377## DBGrids w praktyce i przykłady
13721378
13731379### Przykład: Jak ustawić edytor memo dla dbgrids
13741380
13751381Możesz oczywiście użyć innej kontrolki zamiast TMemo. Dostosuj według gustu. Zaadaptowane z [1](http://forum.lazarus.freepascal.org/index.php?topic=3640.0) (uproszczone użycie właściwości SelectedFieldRect, zobacz [2](http://forum.lazarus.freepascal.org/index.php/topic,8713.msg43288.html#msg43288))
13761382
13771383- Umieść kontrolkę memo (lub jakąkolwiek kontrolkę, którą chcesz) na formularzu, ustaw dowolne właściwości i ustaw jej widoczność na False. Będzie ona używana podczas edycji komórki siatki. W tym przykładzie użyjemy GridCellMemo.
13781384- W zdarzeniu OnSelectEditor umieść następujący kod - dostosuj go, jeśli nie chcesz edytować kolumny logicznej 3, kolumny fizycznej 4:
13791385
13801386``` pascal
13811387 if (Column.DesignIndex = 3) then
13821388 begin
13831389 GridCellMemo.BoundsRect := DbGrid.SelectedFieldRect;
13841390 GridCellMemo.Text:=Column.Field.AsString;
13851391 Editor := GridCellMemo;
13861392 end;
13871393```
13881394
13891395- Załóżmy, że Twoje źródło danych nazywa się Datasource1, a DBGrid nazywa się ResultsGrid. Następnie w zdarzeniu OnEditingDone dla GridCellMemo umieść następujące elementy:
13901396
13911397(Pierwotny post na forum wykorzystywał zdarzenie OnChange, które uruchamia się za każdym razem, gdy zawartość jest zmieniana. Użycie OnEditingDone jest uruchamiane dopiero po zakończeniu edycji przez użytkownika.)
13921398
13931399``` pascal
13941400 if not(Datasource1.State in [dsEdit, dsInsert]) then
13951401 Datasource1.Edit;
13961402
13971403 Datasource1.DataSet.FieldByName(ResultsGrid.SelectedField.FieldName).AsString:=GridCellMemo.Text;
13981404```
13991405
14001406*Uwaga*' Używanie normalnej kontrolki jako niestandardowego edytora ma wiele wad: nie zmieni rozmiaru ani nie zmieni położenia podczas zmiany rozmiaru kolumn lub przewijania siatki, musisz zadbać o modyfikację danych w siatce (jak wyjaśniono powyżej), nie działa poprawnie z DbGrids i zakłóca normalną nawigację po siatce za pomocą klawiatury. Siatka współdziała z edytorem za pomocą specjalnych komunikatów siatki, więc lepiej jest utworzyć podklasę kontrolki w celu zarządzania tymi komunikatami, jak wyjaśniono w rozdziale piątym [tego dokumentu](http://www.freepascal.org/~michael/articles/grids/grids.pdf).
14011407
14021408**Uwaga** Jeśli masz więcej niż jedną siatkę na tej samej formie, użyj innego niestandardowego edytora dla każdej z nich: jeśli użyjesz tego samego elementu sterującego, wydarzą się złe rzeczy, ponieważ obie siatki będą próbowały użyć go jednocześnie.
14031409
14041410### Przykład: Unikaj wyświetlania pól tekstowych jako „(Memo)” dla DBGrids
14051411
14061412When you use SQL statements like "Select * from A" you might see "(Memo)" instead of your content in a grid cell. There are many ways to fix this, but maybe the easiest is to change your statement "Select * from A" to "Select Cast(Column as TEXT) as Column from A". This is a common problem when you use a DBGrid component.
14071413
14081414Gdy używasz instrukcji SQL, takich jak „Select * From A”, możesz w komórkach siatki zobaczyć tekst „(Memo)” zamiast rzeczywistej zawartości. Jest wiele sposobów, aby to naprawić, ale być może najłatwiej jest zmienić instrukcję „Select * From A” na „Select Cast(Column as TEXT) as Column From A”. Jest to powszechny problem, gdy używasz komponentu DBGrid.
14091415
14101416``` pascal
14111417 var
14121418 sql : UTF8String;
14131419 Queryu : TSQLQuery;
14141420.....
14151421 sql := 'SELECT cast(Name as TEXT) as Name FROM Client';
14161422 Queryu.SQL.Text:=sql;
14171423```
14181424
14191425### Sortowanie kolumn lub wierszy w DBGrid ze strzałkami sortowania w nagłówku kolumny
14201426
14211427To jest przykład, który sortuje **DBgrid** przy użyciu zdarzenia **OnTitleClick** oraz **TSQLQuery** i indeksów. Powinno to również działać w przypadku dowolnego zgodnego zestawu danych, takiego jak **TbufDataset**. Funkcja używa właściwości **Column.Tag** do przechowywania stanu sortowania dla każdej klikniętej kolumny, więc gdy wrócisz do już posortowanej kolumny, wybierze odpowiednią strzałkę sortowania do wyświetlenia.
14221428
14231429**Warunki wstępne:**
14241430
14251431- Będzie potrzebny ImageList do przechowywania strzałek sortowania w górę/w dół. Przypisz swoją kontrolkę ImageList do właściwości **TitleImageList** dbgrid.
14261432- Upewnij się, że **[[doc:fcl/sqldb/tsqlquery.maxindexescount.html|TSQLQuery.MaxIndexesCount]]** jest wystarczająco duży, aby pomieścić nowe indeksy, które będziesz tworzyć. W tym przykładzie ustawiłem je na 100.
14271433- Będzie także potrzebna prywatna zmienna do przechowywania ostatniej kolumny użytej do sortowania. W tym przykładzie nazwałem ją **FLastColumn**.
14281434
14291435W tym przykładzie użyty **TSQLQuery** nazywa się OpenQuery.
14301436
14311437Aby ponownie użyć komponentu **TSQLQuery** z inną instrukcją SQL, indeksy muszą zostać wyczyszczone po sortowaniu, w przeciwnym razie zostanie zgłoszony wyjątek podczas otwierania **TSQLQuery** z inną instrukcją SQL.
14321438
14331439``` pascal
14341440FLastColumn: TColumn; //przechowuj ostatnią kolumnę siatki, według której sortowaliśmy
14351441
14361442procedure TSQLForm.ResultsGridTitleClick(Column: TColumn);
14371443const
14381444 ImageArrowUp=0; //powinien pasować do obrazu na ImageList
14391445 ImageArrowDown=1; //powinien pasować do obrazu na ImageList
14401446var
14411447 ASC_IndexName, DESC_IndexName:string;
14421448 procedure UpdateIndexes;
14431449 begin
14441450 // Upewnij się, że definicje indeksów są aktualne
14451451 OpenQuery.IndexDefs.Updated:=false; {<<<--Ta linia jest krytyczna. IndexDefs.Update nie zostanie
14461452 zaktualizowany, jeśli jest już ustawiony na True, co nastąpi w pierwszej posortowanej kolumnie.}
14471453 Openquery.IndexDefs.Update;
14481454 end;
14491455begin
14501456 ASC_IndexName:='ASC_'+Column.FieldName;
14511457 DESC_IndexName:='DESC_'+Column.FieldName;
14521458 // indeksy nie mogą sortować typów binarnych, takich jak ftMemo, ftBLOB
14531459 if (Column.Field.DataType in [ftBLOB,ftMemo,ftWideMemo]) then
14541460 exit;
14551461 // sprawdź, czy indeks sortowania rosnąco już istnieje dla tej kolumny.
14561462 // jeśli nie, utwórz go
14571463 if OpenQuery.IndexDefs.IndexOf(ASC_IndexName) = -1 then
14581464 begin
14591465 OpenQuery.AddIndex(ASC_IndexName,column.FieldName,[]);
14601466 UpdateIndexes; //ensure index defs are up to date
14611467 end;
14621468 // sprawdź, czy indeks sortowania malejąco już istnieje dla tej kolumny.
14631469 // jeśli nie, utwórz go
14641470 if OpenQuery.IndexDefs.IndexOf(DESC_IndexName) = -1 then
14651471 begin
14661472 OpenQuery.AddIndex(DESC_IndexName,column.FieldName,[ixDescending]);
14671473 UpdateIndexes; //ensure index defs are up to date
14681474 end;
14691475
14701476 // Użyj właściwości Tag kolumny, aby przełączyć ASC/DESC
14711477 column.tag := not column.tag;
14721478 if boolean(column.tag) then
14731479 begin
14741480 Column.Title.ImageIndex:=ImageArrowUp;
14751481 Openquery.IndexName:=ASC_IndexName;
14761482 end
14771483 else
14781484 begin
14791485 Column.Title.ImageIndex:=ImageArrowDown;
14801486 OpenQuery.IndexName:=DESC_IndexName;
14811487 end;
14821488 // Usuń strzałkę sortowania z poprzedniej kolumny, którą posortowaliśmy
14831489 if (FLastColumn <> nil) and (FlastColumn <> Column) then
14841490 FLastColumn.Title.ImageIndex:=-1;
14851491 FLastColumn:=column;
14861492end;
14871493```
14881494
14891495### Wybieranie rekordów w DBGrid za pomocą pól wyboru
14901496
14911497Celem jest umożliwienie wyboru dowolnych rekordów w dbgrid za pomocą pól wyboru (CheckBox), siatka ma możliwość automatycznego wyświetlania pól wyboru po wykryciu pól logicznych, dla innych typów pól użytkownik może ręcznie wybrać styl przycisku cbsCheckboxColumn dla kolumny. W przypadku tego rodzaju kolumn wystarczy kliknąć pole wyboru, a zawartość pola zostanie odpowiednio zmodyfikowana.
14921498
14931499Ale co się stanie, jeśli w naszym zbiorze danych nie będzie takiego dostępnego pola? Czy nie chcemy, aby siatka wchodziła w stan edycji po zaznaczeniu pola wyboru? Dodanie kolumny bez pola z ButtonStyle=cbsCheckboxColumn spowoduje wyświetlenie wszystkich pól wyboru wyszarzone i wyłączone, ponieważ nie ma pola połączonego z tą kolumną, a więc nie ma nic do modyfikacji. Ponieważ chcemy sami obsłużyć stan pola wyboru, musimy przechowywać stan gdzieś dla każdego rekordu. W tym celu możemy użyć klasy TBookmarkList (zdefiniowanej w module dbgrids.pas), gdzie właściwość CurrentRowSelected może poinformować, czy bieżący rekord jest zaznaczony, czy nie. Za pomocą zdarzeń dbgrid OnCellClick i OnUserCheckboxState możemy śledzić stan pola wyboru.
14941500
14951501Zauważ, że ta technika wymaga Lazarusa w rewizji r31148 lub nowszego, który implementuje zdarzenie OnUserCheckboxState.
14961502
14971503``` pascal
14981504...
14991505uses ..., dbgrids, stdctrls, ...
15001506
15011507type
15021508
15031509 { TForm1 }
15041510
15051511 TForm1 = class(TForm)
15061512 ...
15071513 procedure DBGrid1CellClick(Column: TColumn);
15081514 procedure DBGrid1UserCheckboxState(sender: TObject; column: TColumn; var AState: TCheckboxState);
15091515 procedure FormCreate(Sender: TObject);
15101516 procedure FormDestroy(Sender: TObject);
15111517 ...
15121518 private
15131519 RecList: TBookmarklist;
15141520 ...
15151521 end;
15161522
15171523procedure TForm1.DBGrid1CellClick(Column: TColumn);
15181524begin
15191525 if Column.Index=1 then
15201526 RecList.CurrentRowSelected := not RecList.CurrentRowSelected;
15211527end;
15221528
15231529procedure TForm1.FormCreate(Sender: TObject);
15241530begin
15251531 RecList := TBookmarkList.Create(DbGrid1);
15261532end;
15271533
15281534procedure TForm1.FormDestroy(Sender: TObject);
15291535begin
15301536 RecList.Free;
15311537end;
15321538
15331539procedure TForm1.DBGrid1UserCheckboxState(sender: TObject; column: TColumn; var AState: TCheckboxState);
15341540begin
15351541 if RecList.CurrentRowSelected then
15361542 AState := cbChecked
15371543 else
15381544 AState := cbUnchecked;
15391545end;
15401546```
15411547
15421548### Przykład: Jak wyeksportować DBGrid do pliku tekstowego
15431549
15441550Istnieje kilka sposobów na utworzenie pliku tekstowego z zawartości DBGrid. Zwykle ludzie powiedzą ci, że zamiast myśleć o DBGrid jako kontenerze danych, należy spojrzeć na niego jak na połączony zestaw danych. Ale co się stanie, gdy reprezentacja tekstowa, którą chcesz uzyskać, musi pasować do wyglądu siatek, widoczności kolumn, szerokości lub kolejności? Jednym z rozwiązań jest użycie pakietu LazReport, który ma składnik przeznaczony specjalnie do tworzenia raportu z DbGrid, raport ten można następnie wyeksportować do kilku innych formatów, w tym do formatu tekstowego. Tutaj przedstawiono inne proste rozwiązanie, które może być również wykorzystane jako podstawa dla innych eksporterów formatów tekstowych, na przykład prostego eksportera html.
15451551
15461552``` pascal
15471553// aGrid: Siatka do wyeksportowania
15481554// lpp: Ilość linii na stronę. Bez nagłówka tekstu
15491555// pageBreak: Czy wstaw podział strony. Niektóre drukarki mogą użyć tego do rozpoczęcia nowej strony
15501556// wymagania: moduł LazUTF8
15511557function GridTextExporter(aGrid: TDbGrid; lpp: Integer; pageBreak:boolean): TStringList;
15521558const
15531559 PX_PER_CHAR = 7;
15541560
15551561var
15561562 Ds: TDataset;
15571563 book: TBookMark;
15581564 recCount: Integer;
15591565 line: string;
15601566 column: TColumn;
15611567
15621568 function WidthToChar(aWidth: Integer): integer;
15631569 begin
15641570 result := trunc(aWidth/PX_PER_CHAR);
15651571 end;
15661572
15671573 procedure AddNext(theText: string; alignment: TAlignment);
15681574 var
15691575 width: Integer;
15701576 begin
15711577 if (line<>'') and (line<>#12) then
15721578 line := line + ' ';
15731579
15741580 width := WidthToChar(Column.Width);
15751581
15761582 case Alignment of
15771583 taRightJustify: line := line + UTF8PadLeft(theText, width);
15781584 taCenter: line := line + UTF8PadCenter(theText, width);
15791585 else line := line + UTF8PadRight(theText, width);
15801586 end;
15811587 end;
15821588
15831589 procedure CollectHeader;
15841590 begin
15851591 AddNext(Column.Title.Caption, Column.Title.Alignment);
15861592 end;
15871593
15881594 procedure CollectField;
15891595 var
15901596 field: TField;
15911597 begin
15921598 field := Column.Field;
15931599
15941600 if (field.DataType=ftMemo) and (dgDisplayMemoText in aGrid.Options) then
15951601 AddNext(field.AsString, Column.Alignment)
15961602 else if Field.DataType<>ftBlob then
15971603 AddNext(field.DisplayText, Column.Alignment)
15981604 else
15991605 AddNext('(blob)', Column.Alignment);
16001606 end;
16011607
16021608 procedure LoopColumns(printingRecord: boolean);
16031609 var
16041610 c: TCollectionItem;
16051611 begin
16061612 if (not printingRecord) and pageBreak and (result.count>0) then
16071613 line := #12
16081614 else
16091615 line := '';
16101616 for c in aGrid.Columns do begin
16111617 Column := TColumn(c);
16121618 if Column.Visible and (Column.Width>=PX_PER_CHAR) then begin
16131619 if printingRecord then CollectField
16141620 else CollectHeader;
16151621 end;
16161622 end;
16171623 result.add(line);
16181624 end;
16191625
16201626begin
16211627 result := TStringList.create;
16221628 Ds := aGrid.DataSource.DataSet;
16231629 Ds.DisableControls;
16241630 book := Ds.GetBookmark;
16251631 try
16261632 Ds.First;
16271633 recCount := 0;
16281634 while not DS.EOF do begin
16291635 if RecCount mod lpp = 0 then
16301636 LoopColumns(false);
16311637 LoopColumns(true);
16321638 inc(recCount);
16331639 Ds.Next;
16341640 end;
16351641 finally
16361642 Ds.GotoBookmark(book);
16371643 Ds.FreeBookmark(book);
16381644 Ds.EnableControls;
16391645 end;
16401646end;
16411647```
16421648
16431649Aby skorzystać z tej funkcji, wystarczy wykonać to:
16441650
16451651``` pascal
16461652var
16471653 L: TStringList;
16481654begin
16491655 L := GridTextExporter(grid, 80, true);
16501656 L.SaveToFile('grid.txt');
16511657 L.Free;
16521658end;
16531659```
16541660
16551661------------------------------------------------------------------------
16561662
16571663**Tłumaczenie**
16581664
16591665Na język polski przełożył: --Sławomir Załęcki ([[User talk:Slawek|talk]]) 17:13, 2 February 2022 (CET)
16601666
16611667---
16621668*From the Free Pascal wiki, page "Grids Reference Page/pl", as it stood on 2022-02-02 after a change by Slawek, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history