Kolorowanie StringGrida w dowolny sposób

0

Witam

Przeszukuje forum na temat kolorowania komórek StringGrid, ale niestety nie znajduję kompletnego artykułu na ten temat. W sieci znajdują się małe wątki, może ktoś zdecydował by się temat opisać od początku do końca z przykładowym kodem a mianowicie.

Programowo:

  1. Zaznaczyć dowolny zakres komórek w Stringgrid za pomocą pętli na jakiś kolor.
  2. Wydzielić dowolne komórki, aby nie były zaznaczane za pomocą pętli.
  3. Po naciśnięciu na nagłówek kolumny czy wiersza, aby linia się zaznaczyła i nie zaznaczała wybranych komórek już zaznaczonych na inny kolor.
  4. Zliczanie komórek pokolorowanych na różne kolory ( zwykła statystyka).
  5. Możliwość zaznaczania za pomocą myszki zakresu komórek bez już zaznaczonych
  6. Zaznaczanie pojedyńczych komórek i ich odznaczanie.
  7. Zaznaczanie komórek bez możliwości zaznaczania zdefiniowanych na początku typu [0,1], [3,3] itp.
  8. Wszystkie te zdarzenia powinny być sterowane za pomocą przycisku Button lub OnClickStringgrid.

Podałem kilka możliwości kolorowania lub też zaznaczania lub odznaczania komórek lista ta może być większa, ale myślę, że na początek wystarczy odnośnie samego kolorowania komórek. Oczywiście malowanie ich w zdarzeniu OnDrawCell powoduje odświeżanie tekstu następująca linia wpisana na końcu zdarzenia OnDrawCell

DrawText(Canvas.Handle, PChar(Cells[ACol,ARow]),length(Cells[ACol,ARow]),Rect,DT_WORDBREAK);  

Jeżeli ktoś znajdzie czas i ma taką wiedzę jak problem rozwiązać to bardzo proszę o podanie propozycji systemowej w postaci gotowego przykładu tak aby każdy mógł przeanalizować podany sposób. Dobrze by było aby kody nie był napisany np. tak

Stringgrid1.RowColor[1] := clInfoBk;
Stringgrid1.RowColor[2] := clInfoBk;

itp. ponieważ każdą czynność można zrobić ręcznie i na piechotę, dobrze by było, aby cały kod, tam gdzie się da, był napisany w postaci pętli np

with StringGrid1 do
     for i:=0 to ColCount-1 do
         for j:=0 to RowCount-1 do
        Cells[i,j]:= clInfoBk;

Innymi słowy aby wszystko było maksymalnie zautomatyzowane ponieważ dla tablicy [10,10] dużo można zrobić ręcznie ale dla tablicy [1000,1000] już nie. Wyświetlenie takiej ilości danych powinno być przejrzyste i klarowne. Prezentacja danych jest ważna z uwagi na ich charakter. Dla przykładu można powiedzieć iż proszę zaznaczyć tylko parzyste liczby lub tylko pełne dziesiątki itd.

Kończąc proszę o rozwiązanie problemu a zapewne wszystkim taki sposób widzenia się przyda.

pozdrawiam
dluzszy

dodanie znaczników <code class="delphi"> - furious programming

0

Proszę od początku do końca:

Jeżeli potrzebujesz zaawansowanego kolorowania zamień StringGrida na VirtualStringTree.

1

Do formatowania zawartości cel StringGrid-a można wykorzystać property Objects [ACol, ARow: Integer]: TObject; i zdarzenie OnDrawCell stringgrid-a, np.

 type
   TInfoCell = record //przykładowa struktura przechowująca informacje o formatowaniu określonej celi
                 FontSize: Integer;
                 FontColor: TColor;
                 CellColor: TColor;
                 Centruj: Boolean;
              end;

   PInfoCell = ^TInfoCell; //wskaźnik na strukturę


procedure TForm1.FormCreate(Sender: TObject);
Var
 k, w: Integer;
 InfoCell: PInfoCell;
begin
  with StringGrid1 do //ustawienia StringGrid-a
  begin
    DefaultDrawing := false;
    DefaultColWidth := 120;
    RowCount := 10;
    ColCount := 4;
  end;

  for k := 0 to StringGrid1.ColCount - 1 do //pętle przykładowego ustawiania tekstu celi i jej formatowania
    for w := 0 to StringGrid1.RowCount - 1 do
      begin
        StringGrid1.Cells[k,w] := 'Cela ' + IntToStr(k) + ',' + IntToStr(w);

        New(InfoCell); //przydzielenie pamięci na strukturę przechowującej informacje o formatowaniu określonej celi

        InfoCell^.FontSize := 6 + w; //czcionka tekstu celi tym większa im większy index wiersza celi
        If w mod 2 = 0 then InfoCell^.FontColor := clRed //w co drugim wierszu stringgrida kolor czcionki czerwony lub niebieski
                       else InfoCell^.FontColor := clBlue;
        If w < 4 then InfoCell^.CellColor := clYellow //dla wierszy o indeksie < 4  żółty kolor wypełnienia celi, dla dalszych wodny
                 else InfoCell^.CellColor := clAqua;
        InfoCell^.Centruj := k=2; //centrowanie tekstu dla kolumny o indeksie 2

        StringGrid1.Objects[k,w] := Pointer(InfoCell); //przypisanie do celi [k,w] wskaźnika na strukturę zawierająca informację o formatowaniu celi
      end;
end;


procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;  Rect: TRect; State: TGridDrawState); //zdarzenie OnDrawCell StringGrid-a
 Var                           
   FormatFlags: Cardinal;
begin
  StringGrid1.Canvas.Font.Size := PInfoCell(StringGrid1.Objects[aCol,aRow])^.FontSize; //formatowanie rozmiaru czcionki
  StringGrid1.Canvas.Font.Color := PInfoCell(StringGrid1.Objects[aCol,aRow])^.FontColor; //formatowanie koloru czcionki
  StringGrid1.Canvas.Brush.Color := PInfoCell(StringGrid1.Objects[aCol,aRow])^.CellColor; //formatowanie koloru wypełnienia celi
  StringGrid1.Canvas.FillRect(Rect);
  FormatFlags:=DT_WORDBREAK+DT_MODIFYSTRING;
  if PInfoCell(StringGrid1.Objects[aCol,aRow])^.Centruj then //jeśli tekst w celi ma być wycentrowany, to ustawienie dodatkowej flagi
    FormatFlags := FormatFlags+DT_CENTER;

  DrawText(StringGrid1.Canvas.Handle, PChar(StringGrid1.Cells[ACol, aRow]), Length(StringGrid1.Cells[ACol, aRow]), Rect, FormatFlags);
end;


procedure TForm1.FormDestroy(Sender: TObject);
 Var
  k, w: Integer;
begin
  for k := 0 to StringGrid1.ColCount - 1 do
    for w := 0 to StringGrid1.RowCount - 1 do
      Dispose(PInfoCell(StringGrid1.Objects[k,w])); //zwalnianie pamięci zajętej przez rekordy
end;
 

Bazując na powyższym przykładzie, wystarczy dostosować strukturę TInfoCell do własnych potrzeb, ustawić odpowiednio jej pola w zależności od współrzędnych celi oraz wykorzystać parametr State: TGridDrawState ze zdarzenia OnDrawCell.

0

@dluzszy - przeczytałem ten wątek kilka razy i nadal nie wiem jakie jest jego przeznaczenie; Nie zadałeś pytania, wymieniłeś jedynie funkcjonalność, której komponent TStringGrid nie posiada, a którą trzeba by dorobić; Nie wiem za bardzo co Tobie odpisać...

Komponent TStringGrid posiada pewną funkcjonalność, z której trzeba skorzystać; Jeśli chemy uzyskać coś więcej - musimy albo rozwinąć klasę komponentu, albo obsługiwać go zewnętrznie, co jest raczej niepraktyczne (kilka instancji kompoenentu wyjaśnia problemowość);

Samo zaznaczanie grup komórek jest obsługiwane przez klasę komponentu, więc zdarzenie OnDrawCell jest wywoływane; W zdarzeniu tym możemy uzyskać praktycznie każdy wymyślony efekt, jednak dane o typie komórek, ich kolorze itd. gdzieś przechowywać trzeba; Bez względu na to, czy dane komórek zapisane będą w klasie komponentu, czy całkowicie na zewnątrz - zdarzenie odpowiedzialne za malowanie komórek musi mieć do nich dostęp i w locie z nich korzystać, aby właściwie dobrać kolory komórki;

W Twoim przykładzie wykorzystujesz funkcje WinAPI do malowania tekstu; Nie wiem czy to dobrze, skoro przecież klasa TCanvas posiada mnóstwo metod do malowania różnych rzeczy, w tym TextOut do rysowania tekstu; Na funkcje WinAPI skusiłbym się jedynie w przypadku, gdybym zaprogramował sobie klasę komponentu całkowicie od podstaw; Choć to i tak niepotrzebne, dlatego że każdy komponent wizualny (okienkowy lub graficzny) posiada na pokładzie pośredniczącą w malowaniu klasę TCanvas;

Kończąc proszę o rozwiązanie problemu a zapewne wszystkim taki sposób widzenia się przyda.

Na pewno, jednak trzeba poświęcić czasu na:

  • rozgryzienie tematu,
  • rozwinięcie klasy komponentu o implementację dodatkowych ficzerów,
  • przetestowanie uzyskanej klasy,
  • napisanie artykułu bądź innego tekstu, wyjaśniajacego uzyskany efekt;
    Z reguły tego typu teksty się nie pojawiają, dlatego że czas programisty jest cenny, podobnie jak nabyta wiedza i umiejętności praktyczne; Duża liczba programistów tworzy takie komponenty i je sprzedaje, a nie rodaje - nie trudno się domyślić dlaczego;

Ja sam będę w najbliższych miesiącach pracował nad zestawem własnych komponentów, wszelakiej maści, których VCL czy LCL nie udostępnia; Poza tym biblioteki te oferują komponenty, których nie możemy malować jak pasuje; Wszędzie sa ograniczenia czy narzuty natywnych kształtów czy kolorów; Ciągle trzeba kombinować, żeby dostosować interfejs aplikacji pod własne wymagania; Nie można tego, nie wolno tamtego, tutaj nie mamy dostępu, tam z kolei czegoś brakuje...

To smutne, że wypracowanie całkowicie własnego i przede wszystkich niezależnego od systemu schematu albo kosztuje mnóstwo czasu i pracy, albo czapki pieniędzy; Ale takie mamy czasy, że wolontariuszy mało, stąd i dobrych i darmowych komponentów mało; A większość programistów biorących sprawę w swoje ręce prędzej czy później zrozumie, że za taki nakład pracy należy się zapłata, więc dobre zestawy komponentów kosztują.

0

Cześć

Całkowicie się z Tobą zgadzam że praca nad komponentami to nie praca wolontariusza. Mając to na uwadze nie proszę o zestaw komponentów lecz o drobny mechanizmy, a mianowicie
nie zadając pytania miałem na myśli ciąg możliwości.

  1. Za pomocą pętli kolorujemy komórki stringgrida na przykład po przekątnej ( Diagonalnej)
  2. Naciskając nagłówek kolumny kolorujemy kolumnę z wyłączeniem tej komórki, która została pokolorowana
  3. Mogę pojedyńczo zaznaczać każdą komórkę i kolor zostaje i zaznaczam drugą . Kikam dwukrotnie i zwalniam zaznaczony kolor tak jak z chekbox
  4. Zakaz zaznaczania komórek fix( kolumna 0 i wiersz 0 )
  5. Wpisanie do tablicy adresu komórki wraz z informacją że dana komórka jest zaznaczona może to być ( 1 zaznaczona; 0 odznaczona; 2 neutralna)
  6. Zmiana koloru " wiejskiej ramki " - nie koniecznie wycięcie - może być ten sam kolor co komórka pokolorowana.
  7. Możliwość zaznaczenia myszką całego stringgrida bez zaznaczania już zaznaczonych komórek na diagonalnej.

tak więc funkcjonalność jest pytaniem

To co mi przekazałeś jest super podoba mi się podejście ( TInfoCell = record //przykładowa struktura przechowująca informacje o formatowaniu określonej celi) trzymania tych informacji w tablicy rekordów.

Cały kod uruchomiłem i jeśli to się zrobi to nie trzeba pisać komponentu bo to jest jedyna funkcjonalność, która w sprawie sterowania Stringgridem załatwia wiekszość problemów

odnośnie innych możliwości to firma Tms Software jako przykłady podaje 86 różnych propozycji i są one OK. Ale niestety tej funkcjonalności o której piszę nie ma.

Jak możesz pomóc to proszę.
dłuższy
Sławomir Ślusarczyk

0

Tak jak napisałem wcześniej - informacje o stylu kolorowania danych komórek i ich przeznaczeniu musisz gdzieś przechowywać; Te dane będą potrzebne do ustawienia kolorów w zdarzeniu OnDrawCell; Reszta to tylko wyobraźnia, bo w ten sposób można zrobić praktycznie dowolne malowanie komórek, łącznie ze wstawianiem obrazków i innymi bajerami;


Ja na szybko machnąłem programik testowy, który zezwala na malowanie różnych komórek różnymi kolorami i stylami dla fontów, blokuje możliwość zaznaczenia zablokowanych komórek, oraz pozwala na zaznaczanie całych zakresów komórek; Informacje na temat komórek przechowywane są w macierzy, zadeklarowanej w polu klasy formularza; To jedynie dla testu, bo wypada takie informacje trzymać wewnątrz komponentu (np. w obiektach komórek); Jest ubogi, bo to tylko testowa aplikacja;

Deklaracja rekordu, zawierającego informacje na temat pojedynczej komórki komponentu:

type
  { single cell information record }
  TStringGridCellInfo = record
    Standard: record
      FontColor: TColor;
      BackColor: TColor;
    end;
    Highlighted: record
      FontColor: TColor;
      BackColor: TColor;
    end;
    CanHighlight: Boolean;
  end;

type
  { array of cells information record }
  TStringGridCellsInfoArr = array [1 .. 10, 1 .. 10] of TStringGridCellInfo;

Następnie macierz tego typu zadeklarowana jest w polu klasy formularza (ale wypada to zmienić):

type
  TMainForm = class(TForm)
    {...}
  private
    CellsInfoArr: TStringGridCellsInfoArr;
  end;

W konstruktorze klasy formularza wypełniam komórki komponentu (aby komórki zawierały jakiś tekst), a także wypełniam komórki macierzy z informacjami o ich typie i kolorach:

procedure TMainForm.FormCreate(Sender: TObject);
var
  intCol, intRow: Integer;
begin
  { fill grid cells }
  for intCol := 0 to sgPreview.ColCount - 1 do
    for intRow := 0 to sgPreview.RowCount - 1 do
      sgPreview.Cells[intCol, intRow] := Format('%d,%d', [intCol, intRow]);

  { fill cells info array }
  for intCol := Low(CellsInfoArr) to High(CellsInfoArr) do
    for intRow := Low(CellsInfoArr[intCol]) to High(CellsInfoArr[intCol]) do
    begin
      { colors for standard cells }
      CellsInfoArr[intCol, intRow].Standard.FontColor := clWindowText;
      CellsInfoArr[intCol, intRow].Standard.BackColor := clWindow;
      { colors for highlighted cells }
      CellsInfoArr[intCol, intRow].Highlighted.FontColor := clHighlightText;
      CellsInfoArr[intCol, intRow].Highlighted.BackColor := clMenuHighlight;
      { cells "can highlight" state }
      CellsInfoArr[intCol, intRow].CanHighlight := True;
    end;

  { set diagonal cells info - block them }
  for intCol := Low(CellsInfoArr) to High(CellsInfoArr) do
  begin
    { colors for cell }
    CellsInfoArr[intCol, intCol].Standard.FontColor := clWindow;
    CellsInfoArr[intCol, intCol].Standard.BackColor := clRed;
    { cell "can highlight" state }
    CellsInfoArr[intCol, intCol].CanHighlight := False;
  end;

  { set 7th column cells info - block them }
  for intRow := sgPreview.FixedRows to sgPreview.FixedRows + 3 do
  begin
    { colors for cell }
    CellsInfoArr[7, intRow].Standard.FontColor := clBlack;
    CellsInfoArr[7, intRow].Standard.BackColor := clYellow;
    { cell "can highlight" state }
    CellsInfoArr[7, intRow].CanHighlight := False;
  end;
end;

Zbiór blokowanych komórek wybrałem losowo, m.in. blokowanie komórek po przekątnej komponentu, dlatego ze o nich wspomniałeś;

Ostatnią rzeczą jest zdarzenie OnDrawCell, które współpracuje z macierzą z informacjami o komórkach; Pobiera informacje z odpowiedniego elementu macierzy i ustawia kolory dla komórki, a także styl tekstu dla wybranych komórek:

procedure TMainForm.sgPreviewDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  Grid: TStringGrid;
  intX, intY: Integer;
  strCell: AnsiString;
begin
  Grid := Sender as TStringGrid;

  with Grid.Canvas do
  begin
    { cell type (standard or fixed) }
    if (ACol < Grid.FixedCols) or (ARow < Grid.FixedRows) then
    begin
      { colors for fixed cell }
      Font.Color  := clGray;
      Brush.Color := $00D8E9EC;
    end
    else
      { cell state (standard or highlighted) }
      if (gdSelected in State) and CellsInfoArr[ACol, ARow].CanHighlight then
      begin
        { colors for highlighted cell }
        Font.Color  := CellsInfoArr[ACol, ARow].Highlighted.FontColor;
        Brush.Color := CellsInfoArr[ACol, ARow].Highlighted.BackColor;
        { font style for highlighted cell }
        Font.Style := [fsBold];
      end
      else
      begin
        { colors for standard cell }
        Font.Color  := CellsInfoArr[ACol, ARow].Standard.FontColor;
        Brush.Color := CellsInfoArr[ACol, ARow].Standard.BackColor;
        { font style for standard cell }
        Font.Style := [];
      end;

    { cell background }
    FillRect(Rect);

    { cell content }
    strCell := Grid.Cells[ACol, ARow];

    intX := Rect.Left + ((Rect.Right - Rect.Left) - TextWidth(strCell)) div 2;
    intY := Rect.Top + ((Rect.Bottom - Rect.Top) - TextHeight(strCell)) div 2;

    TextOut(intX, intY, strCell);
  end;
end;

Całość przedstawia się tak, jak na poniższym zrzucie (korzystam z kolorów systemowych, np. clMenuHighlight, więc u innych efekt może być nieco inny):

stringgrid.png

Komórki z czerwonym i żółtym tłem są zablokowane i nie można ich podświetlić, natomiast komórki z podświetlonego zakresu mają tło niebieskie; Kolory oraz inne style można dobrać dowolnie, ustawiając je przy wypełnianiu macierzy w konstruktorze klasy formularza.

Testową aplikację, napisaną i przetestowaną pod Delphi7 dołączam do posta w załącznikach.

0

Super ekstra tylko jeszcze jedna prośba czy możesz dopisać fragment kodu w którym to

  1. Gdy kikniemy lewym przyciskiem raz myszką na komórkę to zaznaczenie zostaje, a gdy kikniemy dwa razy do zaznaczenie ginie innymi słowy

chyba trzeba oprogramować zdarzenie onclick i onDbClick w Stringgridzie.

  1. Jeśli nie problem to gdy kiknę na nagłówku kolumny to zaznaczam cały wiersz oraz na nagłówku wiersza. Chodzi za zafiksowane kolumny FixedCols i FixedRows.

  2. Moje próby w zdarzeniu StringGrid1DrawCell

 with StringGrid1 do
  Begin
     if Boolean(StringGrid1.Objects[ACol,ARow]) then
       Begin
        Canvas.FillRect(Rect);
        Canvas.Brush.Color:=clZazn;
        Canvas.FillRect(Rect);
     //   Canvas.Font.Style:=[fsBold];
        Canvas.Font.Color:=clBlue;

       End //if Boolean(StringGrid1.Objects[ACol,ARow])
       else //
       Begin
        Canvas.FillRect(Rect);
        Canvas.Brush.Color:=clNieZazn;
        Canvas.FillRect(Rect);
        Canvas.Font.Style:=[];
        Canvas.Font.Color:=clBlue;
       end;

i oprogramowanie w StringGrid1Click liniką Objects[Col,Row]:= TObject(not Boolean(Objects[Col,Row])); z twoim rozwiązaniem nie chcą chodzić no i prymitywna moja linia do zaznaczenia wiersza Stringgrid1.RowColor[1] := clWindow; nie załatwia problemu ponieważ chcę to zrobić w pętli tak aby wiersz mógłby być zanaczany nie tylko jeden ale np kilka np tak jak w Excelu naciskając ctrl. dotyczy to też kolumny. Oczywiście nie zmieniamy zaznaczonych komórek na diagonalnej.

Ta cała funkcjonalność wtedy zostanie oprogramowana i to jest to co mi jest potrzebne. Notabene Gratuluję znajomości Delphi ja bym nigdy nie wpadł na taki sposób oprogramowania.

Sławek

dodanie znacznika <code class="delphi"> - furious programming

0
  1. Gdy kikniemy lewym przyciskiem raz myszką na komórkę to zaznaczenie zostaje, a gdy kikniemy dwa razy do zaznaczenie ginie innymi słowy

Tzn. chodzi o to, że jak raz klikniemy LPM, to komórka staje się zablokowana (czyli nie można jej podświetlić, tak jak w moim przykładzie są komórki czerwone i żółte), a drugi raz ją odblokowuje? Opisz mi nieco dokładniej, np. krok po kroku, dlatego że późno już i myślenie mam nieco spowolnione;

Notabene Gratuluję znajomości Delphi ja bym nigdy nie wpadł na taki sposób oprogramowania.

Mój przykładowy kod wygląda tak a nie inaczej, dlatego że mało miałem czasu; To nie jest dobra praktyka, dlatego że komponent do własnych działań korzysta z zewnętrznych danych, które zadeklarowane są gdzie indziej, niż w klasie samego komponentu; W ten sposób oczywiście można rozbudowywać komponenty, ale tylko w przypadku, gdy w programie mamy jedną instancję; Przy wielu egzemplarzach trzeba by wiele razy deklarować to samo, a to już mija się z celem;

Dlatego napisałem Ci, że lepszym wyjsciem było by stworzenie nowej klasy komponentu, dziedziczącej po TStringGrid; W takiej klasie można zadeklarować "wewnętrznie" nowe dane, oraz upublicznić je za pomocą właściwości, dodać nowe metody itd.; Dzięki temu aby skorzystać z nowych możliwości, wystarczy położyć komponent na formularzu i tyle; A dodatkowo, takich komponentów będzie można użyć w programie wiele, dlatego że dodatkowe możliwości zaimplementowane są wewnątrz komponentu, więc nie trzeba będzie ich pakować np. do klasy formularza;


No dobra, postaram się strzelić;

Zmodyfikowałem kod tak, że po dwukrotnym kliknięciu na komórkę, zostaje ona zablokowana i przemalowana na odpowiedni kolor, a po ponownym dwukrotnym kliknięciu zostaje odblokowana, a jej kolor i styl powraca;

Zmieniłem deklarację rekordu, przechowującego informacje o pojedynczej komórce, obecnie wygląda tak:

type
  { single cell information record }
  TStringGridCellInfo = record
    { for standard cells }
    Standard: record
      FontColor: TColor;
      BackColor: TColor;
    end;
    { for highlighted cells }
    Highlighted: record
      FontColor: TColor;
      BackColor: TColor;
    end;
    { for blocked cells }
    Blocked: record
      FontColor: TColor;
      BackColor: TColor;
    end;
    { "can highlight" state }
    CanHighlight: Boolean;
  end;

Zmodyfikowałem także kod zdarzenia OnDrawCell, aby dostosować rysowanie wszystkich czterech typów komórek; Poniżej nowy jego kod:

procedure TMainForm.sgPreviewDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  Grid: TStringGrid;
  intX, intY: Integer;
  strCell: AnsiString;
begin
  Grid := Sender as TStringGrid;

  with Grid.Canvas do
  begin
    { fixed cell }
    if (ACol < Grid.FixedCols) or (ARow < Grid.FixedRows) then
    begin
      { font and background colors }
      Font.Color  := clGray;
      Brush.Color := $00D8E9EC;
      { font style }
      Font.Style := [];
    end
    else
      { can highlight the cell }
      if CellsInfoArr[ACol, ARow].CanHighlight then
      begin
        { highlighted cell }
        if gdSelected in State then
        begin
          { font and background colors }
          Font.Color  := CellsInfoArr[ACol, ARow].Highlighted.FontColor;
          Brush.Color := CellsInfoArr[ACol, ARow].Highlighted.BackColor;
          { font style }
          Font.Style := [fsBold];
        end
        else
        { standard cell }
        begin
          { font and background colors }
          Font.Color  := CellsInfoArr[ACol, ARow].Standard.FontColor;
          Brush.Color := CellsInfoArr[ACol, ARow].Standard.BackColor;
          { font style }
          Font.Style := [];
        end;
      end
      else
        { blocked cell }
        begin
          { font and background color }
          Font.Color  := CellsInfoArr[ACol, ARow].Blocked.FontColor;
          Brush.Color := CellsInfoArr[ACol, ARow].Blocked.BackColor;
          { font style }
          Font.Style := [fsBold];
        end;

    { cell background }
    FillRect(Rect);

    { cell content }
    strCell := Grid.Cells[ACol, ARow];
    intX := Rect.Left + ((Rect.Right - Rect.Left) - TextWidth(strCell)) div 2;
    intY := Rect.Top + ((Rect.Bottom - Rect.Top) - TextHeight(strCell)) div 2;

    TextOut(intX, intY, strCell);
  end;
end;

No i samo zdarzenie podwójnego kliknięcia; W nim pobierana jest pozycja kursora na ekranie (bądź pulpicie), następnie koordynaty przeliczane są na współrzędne względem komponentu; Następnie odpowiednią metodą tłumaczone są współrzędne kursora myszy na koordynaty komórki, nad którą znajduje się kursor; Następnie sprawdzane jest, czy komórka, nad którą jest kursor jest "fixed" czy nie; Jeśli nie, to pole CanHighlight jest negowane, a cały komponent przemalowywany (niestety nie mam innego pomysłu na to, jak przemalować tylko jedną komórkę - testuję pod Delphi7);

Kod zdarzenia jest krótki i prosty w zrozumieniu:

procedure TMainForm.sgPreviewDblClick(Sender: TObject);
var
  Grid: TStringGrid;
  ptHover: TPoint;
  gcHover: TGridCoord;
begin
  Grid := Sender as TStringGrid;
 
  { get the cursor coordinates }
  GetCursorPos(ptHover);
  ptHover := ScreenToClient(ptHover);
 
  { get the cell coordinates }
  gcHover := Grid.MouseCoord(ptHover.X, ptHover.Y);
 
  { check the cell type (standard or fixed }
  if (gcHover.X >= Grid.FixedRows) and (gcHover.Y >= Grid.FixedCols) then
  begin
    { update the cell info }
    with CellsInfoArr[gcHover.X, gcHover.Y] do
      CanHighlight := not CanHighlight;

    { repaint grid }
    Grid.Repaint();
  end;
end;

Dzięki temu, możliwe jest blokowanie dwukrotnie klikniętych komórek oraz ich odblokowywanie po ponownym dwukliku; Oczywiście kolory zostawiłem takie, jakie przedstawiłem w poprzednim przykładzie, jednak nic nie stoi na przeszkodzie, aby w tej metodzie oprócz zmiany stanu CanHighlight, zmienić także kolor i styl zablokowanej komórki - należy to zrobić także w zdarzeniu OnDblClick;

Efekt nowego kodu poniżej, dla losowo poblokowanych komórek:

stringgrid.png

Komórki koloru białego to komórki odblokowane i nie zaznaczone, niebieskie są także odblokowane, ale zaznaczone, a czerwone to komórki zablokowane; Czyli zaznaczone są komórki od [4,4] do [9,7];

Myślę, że teraz naświetliłem bardziej sposób dynamicznego kolorowania komórek; W razie pytań - pisz; A program oraz poprawione jego źródła w załączniku.

1 użytkowników online, w tym zalogowanych: 0, gości: 1