Podświetlenie niektórych wierszy na czerwono w StringGrid

0

Witam
Mam taki kodzik i moje pytanie jest jak zrobić aby w StringGrid gdy wartość kolumny 4 jest < od 50 podświetlić wiersze na czerwono

procedure TForm4.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  if (Acol mod 4 <=5 ) and (Arow  <=5)   then
    with TStringGrid(Sender) do
    begin
      //paint the background Green
      Canvas.font.Color := clRed;
          Canvas.FillRect(Rect);
      Canvas.TextOut(Rect.Left+2,Rect.Top+2,Cells[ACol, ARow])  ;

      end;
0

A kazałeś komponentowi wykorzystać Twoje zdarzenie malowania komórek?

Jeśli nie, to odznacz właściwość DefaultDrawing – wtedy komponent będzie używał Twojego zdarzenia i malował komórki w taki sposób, w jaki zechcesz aby to robił.

0

Nie dzięki a jak zdefiniować żeby 4 kolumnę gdy wartość < 50 ? szukam ale jakoś nie mogę nic znaleźć jak to zrobić.

0

Nie dzięki […]

Nie rozumiem – czy Twoje zdarzenie OnDrawCell jest wywoływane, czy nie jest?

[…] a jak zdefiniować żeby 4 kolumnę gdy wartość < 50 ? szukam ale jakoś nie mogę nic znaleźć jak to zrobić.

Przekonwertuj ciąg z komórki na liczbę i porównaj – wykorzystaj StrToInt lub TryStrToInt.

0

Mam SQLQuery powiązane ze StringGridem i chcę zrobić tak aby mi podświetlał na czerwono gdy wartość będzie poniżej 50 w danej kolumnie.

1

@Molnas
@furious programming podał sposób w jaki zmusić stringgrida do malowania przy pomocy Twojego kodu. Ale Twój kod, jeśli nawet zadziała, to nic nie narysuje w sytuacji kiedy warunek nie będzie spełniony i w stringgridzie będziesz miał puste pola.
Aby to zrobić porządnie to masz dwa rozwiązania
a. zapamiętać wskaźnik do domyślnej metody rysowania grida i użyć swojej metody jesli warunek jest spełniony,a w przeciwnym razie użyć standardowej i zapamiętanej metody
b. obsłużyć w kodzie oba warianty rysowania komórki

0

Wielkie dzięki

0

W Lazarusie mogę zrobić tak, że DefaultDrawing zostawiam na True, a w zdarzeniu OnDrawCell definiuję malowanie wybranych komórek – pozostałe będą malowane automatycznie, bo tak wynika to z budowy komponentu. Jeśli zmienię DefaultDrawing na False to muszę obsłużyć malowanie każdej komórki i dla każdego przypadku – w przeciwnym razie nic nie zostanie namalowane.

@grzegorz_so: czy w Delphi działa to tak samo?

0

nie jestem pewien
mam aplikację która w stringridzie wyświetla (rysuje) różne rzeczy, ale z tego co pamiętam to moja metoda rysowania obsługuje rysowanie od początku do końca.
muszę spojrzeć w kod apki

0

sprawdziłem, grid jest tworzony dynamicznie, czyli z kodu i "defaultdrawing" ma ustawione na "false" , więc chyba nie wyjaśnię Twoich wątpliwości. Ale mogę zbudować testową apke i sprawdzić jak działa rysowanie.
Być może StringGrid najpierw sam rysuje komórkę a w drugiej kolejności wywołuje OnDrawCell o ile ta nie jest "nil", czyli zawsze coś się "narysuje".
Niektóre kontrolki, np te dziedziczące z TDBgrid mają metodę "DefaultDrawDataCell", której używam w sytuacji kiedy nie chcę aby mój kod sam coś rysował

0

Co rozumiesz przez podświetlić... bo ja mam wrażenie ze chodzi nie o podświetlenie na o wypisanie wartości czerwoną czcionką wystarczy.

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  Value: Integer;
begin
  if ACol = 4 then //albo 3 nie wiem co rozumiesz przez kolumne 4 index (od zera) czy rzeczywiscie 4
  begin
    Value:= StrToIntDef(TStringGrid(Sender).Cells[ACol, ARow], 0);
    if Value < 50 then
    begin
      TStringGrid(Sender).Canvas.Font.Color:= clRed;
      TStringGrid(Sender).Canvas.TextOut(Rect.Left+2,Rect.Top+2, TStringGrid(Sender).Cells[ACol, ARow]);
    end;
  end;
end;

Oczywiście nie należy ruszać właściwości DefaultDrawing która domyślnie jest na True i tak ma być.

0

@kAzek:

Oczywiście nie należy ruszać właściwości DefaultDrawing która domyślnie jest na True i tak ma być.

myślę że nie masz racji. "DefaultDrawing=true" sprawia że zawsze wykona się domyślne rysowanie stringgrida które może nałożyć się na rysowanie podpięte pod "OnDrwaCell". A jeśli chcemy aby za rysowanie był odpowiedzialny tylko i wyłącznie kod użytkownika to "DefaultDrawing" musi być "false"

0

@grzegorz_so: i tak i nie – jeśli właściwość ta jest zapalona, komponent dla każdej komórki wywołuje wewnętrzną metodę malującą komórki zgodnie ze schematem systemowym. Jeśli nie jest zapalona to jej nie wywołuje. Zdarzenie OnDrawCell wywoływane jest po tym wewnętrznym, więc komórki nie spełaniające warunku pytacza, zostaną pomalowane raz, a te spełniające warunek – dwa razy (raz domyślnie i raz według zdarzenia).

Biorąc pod uwagę post @kAzek, wewnętrzny mechanizm wygląda mniej więcej tak:

if FDefaultDrawing then
  DrawDefault({...});
  
if Assigned(FOnDrawCell) then
  FOnDrawCell({...});

Jeśli odznaczy się DefaultDrawing to w zdarzeniu OnDrawCell trzeba będzie malować każdą komórkę – w przeciwnym razie komórki będą posiadać jakąś niezdefiniowaną zawartość (przypadkowe tło). Pozostawienie DefaultDrawing włączonego pozwoli na własnoręczne malowanie tylko niektórych komórek, a pozostałe malowane będą w stylu domyślnym.

Natomiast sam fakt dwukrotnego przemalowania komórki w niektórych przypadkach raczej nie stanowi problemu.

0

@furious programming:
czyli się zgadzamy że właściwości DefaultDrawing w zależności od sytuacji i wymagań może być albo true albo false

mój ostatni post nawiązywał do postu @kAzek

Oczywiście nie należy ruszać właściwości DefaultDrawing która domyślnie jest na True i tak ma być.

0

@grzegorz_so myślę, że DefaultDrawing ustawia się na False w przypadkach gdy chcemy sami malować wszystko, wtedy rzeczywiście zbędne jest domyślne malowanie a później tego przemalowywanie po swojemu ale w przypadku jednej kolumy (a właściwie tylko niektórych jej wierszy) takie rozwiązanie wydaje mi się lepsze niż malowanie po swojemu wszystkiego jeżeli domyślnie malowana reszta nam odpowiada.

1

Podsumowując, z moich obserwacji wygląda to tak:

DefaultDrawingOnDrawCellprzemalowańopis
Truenil1malowanie w stylu systemowym (domyślne)
Truezdefiniowane2malowanie w stylu systemowym, a następnie według zdarzenia
Falsezdefiniowane1malowanie tylko według zdarzenia
Falsenil0wizualne UB

Czyli w zależności od potrzeb, można wyłączyć lub pozostawić włączoną właściwość DefaultDrawing.

Wiem jak to wygląda w Lazarusie – to opisuje powyższa tabelka. Zachowanie kontrolki w LCL powinno być zgodne z odpowiednikiem z VCL, ale nie mam dostępu do źródeł VCL, więc sam nie sprawdzę.

0
kAzek napisał(a):

Co rozumiesz przez podświetlić... bo ja mam wrażenie ze chodzi nie o podświetlenie na o wypisanie wartości czerwoną czcionką wystarczy.

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  Value: Integer;
begin
  if ACol = 4 then //albo 3 nie wiem co rozumiesz przez kolumne 4 index (od zera) czy rzeczywiscie 4
  begin
    Value:= StrToIntDef(TStringGrid(Sender).Cells[ACol, ARow], 0);
    if Value < 50 then
    begin
      TStringGrid(Sender).Canvas.Font.Color:= clRed;
      TStringGrid(Sender).Canvas.TextOut(Rect.Left+2,Rect.Top+2, TStringGrid(Sender).Cells[ACol, ARow]);
    end;
  end;
end;

Oczywiście nie należy ruszać właściwości DefaultDrawing która domyślnie jest na True i tak ma być.

No tak o to chodzi aby wartości w 4 kolumnie które są mniejsze od 50 były na czerwono.
jak w excel kolumna d

Działa tylko wyświetla czerwony tekst na czarnym. tak jak by dwa były nałożone na siebie. jak wyłączę default.. nie wyświetla pozostałych kolumn.

0
Molnas napisał(a):

Działa tylko wyświetla czerwony tekst na czarnym. tak jak by dwa były nałożone na siebie.

Maluj całą komórkę, a nie tylko sam tekst. Dzięki temu przykryjesz wszystko co domyślna metoda namaluje.

jak wyłączę default.. nie wyświetla pozostałych kolumn.

Nie maluje ich, bo w swoim zdarzeniu nie masz tego oprogramowanego. Jeśli wyłączysz DefaultDrawing, to musisz zadbać o to, aby wszystkie komórki były malowane w zdarzeniu OnDrawCell, nie tylko te wybrane.

0

Może coś nie do końca doprecyzowałem chcę uzyskać jak w excelu formatowanie warunkowe tak aby wartość doprecyzowując z kolumny 3 była innego coloru wtedy gdy jest mniejsza od np. 30 pozostałe > mają być w kolorze standardowym.

cos jak to:

2

Podam przykład działający w Lazarusie:

procedure TForm1.StringGrid1DrawCell(ASender: TObject; ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState);
var
  LGrid: TStringGrid absolute ASender;
begin
  if ACol = 3 then
    LGrid.Canvas.Font.Color := clRed;

  LGrid.DefaultDrawCell(ACol, ARow, ARect, AState);
end;

Prosty kod – jeśli w numer kolumny jest równy 3 to tekst w komórce malowany jest na czerwono, w przeciwnym razie na czarno (kolor domyślny, według bieżącej kompozycji wizualnej systemu). Efekt działania takiego kodu na poniższym zrzucie:

grid.png

Spróbuj w ten sam sposób zapisać kod u siebie, tyle że ze swoim warunkiem.

2

Rzeczywiście mój poprzedni kod działał tylko w starym Delphi 7 a nowym są pozostałości po domyślnym malowaniu tekstu. Sposób zaprezentowany przez @furious programming jest dobry ale ponieważ w Delphi nie ma ma metody DefaultDrawCell (przynajmniej publicznej dla VCL, dla FMX jest) więc trzeba bardziej na piechotę gdyby ktoś potrzebował to:

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  Value: Integer;
  s: String;
  Grid: TStringGrid absolute Sender;
begin
  if (ACol = 4) and (ARow >= TStringGrid(Sender).FixedRows) then
  begin
    s:= Grid.Cells[ACol, ARow];
    Value:= StrToIntDef(s, 0);
    if Value < 50 then
    begin
      Grid.Canvas.Brush.Color := Grid.Color; //albo na sztywno ustawic np. domyslny clWindow;
      Grid.Canvas.FillRect(Rect);
      Grid.Canvas.Font.Color:= clRed;
      InflateRect(Rect, -2, -2);
      Grid.Canvas.TextRect(Rect,  s, [tfLeft, tfSingleLine, tfVerticalCenter]);
    end;
  end;
end;

1.png

0

Kurcze a mi tak nie działa lepsze niż ostatnie ale wciąż if value ... wstawię co kolwiek i tak zaznacza całą kolumnę. Zastanawiam się czy problem nie jest w tym że dane pochodzą z sqlquery

0

To nie ma nic do tego skąd pochodzą dane. Może warunki nie takie if (ACol = 4) to 5 kolumna jak widać na screenie a to if Value < 50 then dla wartości w komórkach mniejszych niż 50. Zawsze możesz użyć debugera i sprawdzić co się dzieje.

0

A u mnie wychodzi jak w załączniku

2

No i mamy jasność nie widzisz że bruździ Ci znak % w takim przypadku Value:= StrToIntDef(s, 0); zawsze zwróci 0 trzeba się go pozbyć. Jednym ze sposobów jest zmiana go na pusty ciąg Value:= StrToIntDef(StringReplace(s, '%', '', []), 0);

0

Ok to pewnie jak mam wynik z wartościami po przecinku będzie to samo :)

I działa pięknie wielkie dzięki za pomoc. Wiele nauki mam jeszcze przed sobą

1

Jeżeli może być wartość ułamkowa to sprawa się trochę bardziej komplikuje:

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  Value: Real;
  s: String;
  Grid: TStringGrid absolute Sender;
  fs: TFormatSettings;
begin
  if (ACol = 4) and (ARow >= TStringGrid(Sender).FixedRows) then
  begin
    s:= Grid.Cells[ACol, ARow];
    fs:= TFormatSettings.Create; //z systemu zostanie separator dziesietny, bo w zaleznosci od ustawien moze to być , (przecinek)  lub . (kropka)
    //mozna też na sztywno ustawic ale tylko jezeli przecinek w warosciach też na sztywno
    //fs.DecimalSeparator:= ',';
    Value:= StrToFloatDef(StringReplace(s, '%', '', []), 0, fs);
    if CompareValue(Value, 50) = -1 then //do uses System.Math
    begin
      Grid.Canvas.Brush.Color := Grid.Color; //albo na sztywno ustawic np. domyslny clWindow;
      Grid.Canvas.FillRect(Rect);
      Grid.Canvas.Font.Color:= clRed;
      InflateRect(Rect, -2, 0); //margines tekstu
      Grid.Canvas.TextRect(Rect,  s, [tfLeft, tfSingleLine, tfVerticalCenter]);
    end;
  end;
end;
0

dzięki ja sobie dla ułatwienia zaokrągliłem w Query wynik .

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