[gelöst] StringGrid und DrawCell

Rund um die LCL und andere Komponenten
DonMigos
Beiträge: 52
Registriert: Mi 15. Mai 2013, 21:21
OS, Lazarus, FPC: Win7 (L 1.0.8 FPC 2.6.2)
CPU-Target: 32Bit

[gelöst] StringGrid und DrawCell

Beitrag von DonMigos »

Hi,
Unter Delphi hatte der Code unten geklappt, aber unter Lazarus bekomme ich nur fehlerhafte Ergebnisse (also falsche Farben an falscher Stelle) damit.
Delphi Mode hilft auch nicht.

Code: Alles auswählen

 
type
  TTestGrid = class(TStringGrid)
  private
  protected
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  public
  end;
 
implementation
 
procedure TTestGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
  ZeilenText: string;
begin
  //erste Spalte einfärben
  if ACol = 0 then
    begin
      Canvas.Brush.Color := clHighlight; //Farbe auswählen zum Zeichnen
      Canvas.FillRect(ARect); // Zelle leer überzeichnen
    end;
 
  //Farbe und Schrift bei Selektion
  if (gdSelected in AState) or (gdFocused in AState) then
  begin
    Canvas.Brush.Color := clgreen; //Farbe auswählen zum Zeichnen
    Canvas.FillRect(ARect); // Zelle leer überzeichnen
    Canvas.Font.Color := clblack;
  end;
 
  ZeilenText := Cells[ACol, ARow]; // Text der Zelle holen
  //Text zentriert zeichnen
  DrawText(Canvas.Handle, PChar(ZeilenText), Length(ZeilenText), ARect, DT_SINGLELINE or DT_Center or DT_VCENTER);
end;
Wenn ich ein inherited an den Anfang setze, klappt das mit den Farben zwar, aber die Schrift wird doppelt gezeichnet...
Zuletzt geändert von DonMigos am Do 20. Jun 2013, 19:18, insgesamt 3-mal geändert.

Scotty
Beiträge: 768
Registriert: Mo 4. Mai 2009, 13:24
OS, Lazarus, FPC: Arch Linux, Lazarus 1.3 r44426M FPC 2.6.4
CPU-Target: x86_64-linux-qt/gtk2
Kontaktdaten:

Re: StringGrid und DrawCell

Beitrag von Scotty »

Hilft "Canvas.Brush.Style:=bsSolid"? Das muss ich zumindest unter Windows oder Linux explizit angeben. Ansonsten gibt meine Glaskugel wenig her... ;-)

Soner
Beiträge: 734
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: StringGrid und DrawCell

Beitrag von Soner »

Am Anfang Inherited aufrufen und setze DefaultDrawing:=false;

Nur um Grid selber zu zeichnen musst du nicht als Klasse ableiten. Du kannst auf dein Formular ein StringGrid hinzufügen und das OnDrawCell auswerten. Da auch DefaultDrawing:=false setzen.

DonMigos
Beiträge: 52
Registriert: Mi 15. Mai 2013, 21:21
OS, Lazarus, FPC: Win7 (L 1.0.8 FPC 2.6.2)
CPU-Target: 32Bit

Re: StringGrid und DrawCell

Beitrag von DonMigos »

Danke für die schnellen Antworten !
Soner hat geschrieben: Nur um Grid selber zu zeichnen musst du nicht als Klasse ableiten. Du kannst auf dein Formular ein StringGrid hinzufügen und das OnDrawCell auswerten.
Ja das ist mir bekannt, allerdings ist meine Ableitung von TStringgrid normal nocht etwas umfangreicher.

Die Vorschläge haben leider nichts gebracht, ich habe sie wie unten eingesetzt.
Der Text 'Hallo' beispielsweise wird zweimal gezeichnet, die Folge davon ist das er einmal zentriet zu sehen ist und einmal linksbündig. Die Farben sind wie gesagt mit dem inherited richtig gesetzt.

Code: Alles auswählen

 type
  TTestGrid = class(TStringGrid)
  private
  protected
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  public
  end;
 
implementation
 
procedure TTestGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
  ZeilenText: string;
begin
  inherited;
  DefaultDrawing:=False;
 
  //erste Spalte einfärben
  if ACol = 0 then
    begin
      Canvas.Brush.Color := clHighlight; //Farbe auswählen zum Zeichnen
      Canvas.FillRect(ARect); // Zelle leer überzeichnen
    end;
 
  //Farbe und Schrift bei Selektion
  if (gdSelected in AState) or (gdFocused in AState) then
  begin
    Canvas.Brush.Color := clgreen; //Farbe auswählen zum Zeichnen
    Canvas.FillRect(ARect); // Zelle leer überzeichnen
    Canvas.Font.Color := clblack;
  end;
 
  ZeilenText := Cells[ACol, ARow]; // Text der Zelle holen
  //Text zentriert zeichnen
  DrawText(Canvas.Handle, PChar(ZeilenText), Length(ZeilenText), ARect, DT_SINGLELINE or DT_Center or DT_VCENTER);
end;
 
Zuletzt geändert von DonMigos am Mo 17. Jun 2013, 21:42, insgesamt 1-mal geändert.

Soner
Beiträge: 734
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: StringGrid und DrawCell

Beitrag von Soner »

... und noch falls die Zelle nicht fokussiert oder ausgewählt ist zeichne es auch sonst hast du falsche Farben:

Code: Alles auswählen

 
  if (gdSelected in AState) or (gdFocused in AState) then
  begin
    Canvas.Brush.Color := clgreen; //Farbe auswählen zum Zeichnen
    Canvas.FillRect(ARect); // Zelle leer überzeichnen
    Canvas.Font.Color := clblack;
  end
  // HIER HINZUFÜGEN !!!!!!!!
   else begin
    Canvas.Brush.Color := clWindow; //Farbe auswählen zum Zeichnen
    Canvas.FillRect(ARect); // Zelle leer überzeichnen
  end;  
 
Und DrawText ist von Windows-Api. Nimm gleich Canvas.TextRect oder Canvas.Texout. Mit Canvas.TextHeight und Canvas.TextWidth kannst du Textmaße bestimmen und selber zentrieren.

Soner
Beiträge: 734
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: StringGrid und DrawCell

Beitrag von Soner »

DefaultDrawing mußt du außerhalb von DrawCell false setzen am besten TTestGrid.Create funktion.

DonMigos
Beiträge: 52
Registriert: Mi 15. Mai 2013, 21:21
OS, Lazarus, FPC: Win7 (L 1.0.8 FPC 2.6.2)
CPU-Target: 32Bit

Re: StringGrid und DrawCell

Beitrag von DonMigos »

Soner hat geschrieben:... und noch falls die Zelle nicht fokussiert oder ausgewählt ist zeichne es auch sonst hast du falsche Farben:

Code: Alles auswählen

 
  // HIER HINZUFÜGEN !!!!!!!!
   else begin
    Canvas.Brush.Color := clWindow; //Farbe auswählen zum Zeichnen
    Canvas.FillRect(ARect); // Zelle leer überzeichnen
  end;  
 
Jetzt wird zwar die Schrift nur einmal und richtig gezeichnet (zentriert), aber die Gitter sind weg und es fehlt die Farbe für die erste Spalte...
DefaultDrawing:= False ist jetzt im Konstruktor.

DonMigos
Beiträge: 52
Registriert: Mi 15. Mai 2013, 21:21
OS, Lazarus, FPC: Win7 (L 1.0.8 FPC 2.6.2)
CPU-Target: 32Bit

Re: StringGrid und DrawCell

Beitrag von DonMigos »

Durch ein paar Änderungen scheint es jetzt zu klappen.
Inherited und DefaultDrawing braucht man mit dieser Methode nicht. (DefaultDrawing hatte bei mir nie eine Wirkung).

Code: Alles auswählen

type
  TTestGrid = class(TStringGrid)
  private
  protected
    procedure MyDrawCell(Sender: TObject; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState);
  public
    constructor Create(AOwner: TComponent); override;
  end;
 
implementation
 
constructor TTestGrid.Create(AOwner: TComponent);
begin
  inherited;
  OnDrawCell:= @MyDrawCell;
end;
 
procedure TTestGrid.MyDrawCell(Sender: TObject; ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
  ZeilenText: string;
begin
  Canvas.Brush.Color := clWindow; //Farbe auswählen zum Zeichnen
  Canvas.FillRect(ARect); // Zelle leer überzeichnen
 
  if ACol = 0 then
  begin
    Canvas.Brush.Color := clHighlight; //Farbe auswählen zum Zeichnen
    Canvas.FillRect(ARect); // Zelle leer überzeichnen
  end;
 
  //Farbe wenn Zelle ausgewählt ist
  if (gdSelected in AState) or (gdFocused in AState) then
  begin
    Canvas.Brush.Color := clgreen; 
    Canvas.FillRect(ARect); 
    Canvas.Font.Color := clblack;
  end;
 
  ZeilenText := Cells[ACol, ARow]; // Text der Zelle holen
  //Text zentriert zeichnen
  DrawText(Canvas.Handle, PChar(ZeilenText), Length(ZeilenText), ARect, DT_SINGLELINE or DT_Center or DT_VCENTER);
end;
Das mit dem TextOut oder TextRect habe ich noch nicht hinbekommen.

Soner
Beiträge: 734
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: StringGrid und DrawCell

Beitrag von Soner »

Das kannst du noch verbessern, wenn eine Zelle in der 0.Spalte ausgewählt ist dann wird es dreimal sonst immer zweimal gezeichnet.
Wenn ich die Quelltexte in den letzten Jahren anschaue, dann weiß ich warum man heutzutage einen Computer mit Intel Core 7 CPU und 8 GB RAM braucht :)
Scherz beiseite mach Zeichnenroutine lieber so:

Code: Alles auswählen

type
procedure TTestGrid.MyDrawCell(Sender: TObject; ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
  ZeilenText: string;
begin
 
  if (gdSelected in AState) or (gdFocused in AState) then   //Wenn die Zelle ausgewählt ist: Farbe wenn Zelle ausgewählt ist
  begin
    Canvas.Font.Color := clblack;
    Canvas.Brush.Color := clgreen; 
  end
  else if ACol = 0 then //Wenn 0.Spalte ist
  begin
    Canvas.Font.Color := clHighlightText;
    Canvas.Brush.Color := clHighlight; //Farbe auswählen zum Zeichnen
  end
  else //sonstige Zellen
  begin
    Canvas.Font.Color := clWindowText;
    Canvas.Brush.Color := clWindow; //Farbe auswählen zum Zeichnen
  end;
  Canvas.FillRect(ARect);  
 
  ZeilenText := Cells[ACol, ARow]; // Text der Zelle holen
  //Text zentriert zeichnen
  DrawText(Canvas.Handle, PChar(ZeilenText), Length(ZeilenText), ARect, DT_SINGLELINE or DT_Center or DT_VCENTER);
end;

DonMigos
Beiträge: 52
Registriert: Mi 15. Mai 2013, 21:21
OS, Lazarus, FPC: Win7 (L 1.0.8 FPC 2.6.2)
CPU-Target: 32Bit

Re: [gelöst] StringGrid und DrawCell

Beitrag von DonMigos »

Ja danke, so ist es natürlich besser !

Und so gehts auch ohne DrawText von der WinApi:

Code: Alles auswählen

procedure TTestGrid.MyDrawCell(Sender: TObject; ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
var
  ZeilenText: string;
  MyTxtStyle: TTextStyle;
begin
  if (gdSelected in AState) or (gdFocused in AState) then //Wenn die Zelle ausgewählt ist
  begin
    Canvas.Font.Color := clblack;
    Canvas.Brush.Color := clgreen; //Farbe wenn Zelle ausgewählt ist
  end
  else if ACol = 0 then //Wenn 0.Spalte ist
  begin
    Canvas.Font.Color := clHighlightText;
    Canvas.Brush.Color := clHighlight; //Farbe auswählen zum Zeichnen
  end
  else //sonstige Zellen
  begin
    Canvas.Font.Color := clWindowText;
    Canvas.Brush.Color := clWindow; //Farbe auswählen zum Zeichnen
  end;
  Canvas.FillRect(ARect);  //Zelle Zeichnen
 
  ZeilenText := Cells[ACol, ARow]; // Text der Zelle holen
  MyTxtStyle.Alignment := taCenter;
  MyTxtStyle.Layout := tlCenter;
  Canvas.TextRect(aRect, aRect.Left, aRect.Top, ZeilenText, MyTxtStyle); //Text zentriert zeichnen
end; 

DonMigos
Beiträge: 52
Registriert: Mi 15. Mai 2013, 21:21
OS, Lazarus, FPC: Win7 (L 1.0.8 FPC 2.6.2)
CPU-Target: 32Bit

Re: StringGrid und DrawCell

Beitrag von DonMigos »

Ein kleines Problem bekomme ich noch nicht weg, es wird am Anfang immer die erste Zelle im Grid mit der Farbe überzeichnet, welche für die Selektion gedacht ist.
Auch wenn ich die Selektion komplett aufhebe bleibt sie in der falschen Farbe.
Zum nachvollziehen habe ich unten den ganzen Code der Unit, kann man direkt so übernehmen zum testen. Ist diesmal mit der Standard Komponente.

Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, Variants, Grids, Forms, Dialogs, Controls,
  StdCtrls, LCLIntf, LCLType, Graphics;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    StringGrid1: TStringGrid;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure StringGrid1DrawCell(Sender: TObject; aCol, aRow: Integer;
      aRect: TRect; aState: TGridDrawState);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
var
  Reihe: Integer = 0;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  with StringGrid1 do
  begin
    Cells[1,1]:= 'Hallo';
    FixedCols := 0;
    FixedRows := 0;
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);  // Ganze Reihen nacheinander markieren
begin
  if Reihe > StringGrid1.RowCount-1 then Reihe:= 0;
  StringGrid1.Selection := TGridRect(Rect(0,Reihe,StringGrid1.ColCount-1,Reihe));
  Inc(Reihe);
end;
 
procedure TForm1.Button2Click(Sender: TObject);  //Auswahl löschen
begin
  StringGrid1.Selection := TGridRect(Rect(-1,-1,-1,-1));
end;
 
procedure TForm1.StringGrid1DrawCell(Sender: TObject; aCol, aRow: Integer;
  aRect: TRect; aState: TGridDrawState);
var
  ZeilenText: string;
  MyTxtStyle: TTextStyle;
begin
  with StringGrid1 do
  begin
    if (gdSelected in AState) then //Wenn die Zelle ausgewählt ist
    begin
      Canvas.Font.Color := clblack;
      Canvas.Brush.Color := clGray; //Farbe wenn Zelle ausgewählt ist
    end
    else if ACol mod 2 = 0 then //Jede zweite Spalte
    begin
      Canvas.Font.Color := clWhite;
      Canvas.Brush.Color := clBlue; //Farbe auswählen zum Zeichnen
    end
    else //sonstige Zellen
    begin
      Canvas.Font.Color := clWindowText;
      Canvas.Brush.Color := clWindow; //Farbe auswählen zum Zeichnen
    end;
    Canvas.FillRect(ARect);  //Zelle Zeichnen
 
    ZeilenText := Cells[ACol, ARow]; // Text der Zelle holen
 
    //Text zentriert zeichnen
    MyTxtStyle.Alignment := taCenter;
    MyTxtStyle.Layout := tlCenter;
    Canvas.TextRect(aRect,aRect.Left, aRect.Top, ZeilenText,MyTxtStyle);
  end;
end;
end.
 

Benutzeravatar
theo
Beiträge: 10907
Registriert: Mo 11. Sep 2006, 19:01

Re: StringGrid und DrawCell

Beitrag von theo »

Naja, ein Feld ist halt immer ausgewählt. Schlimm?

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: StringGrid und DrawCell

Beitrag von MmVisual »

Mache das:

Code: Alles auswählen

if (gdSelected in aState) or (gdFocused in aState) then 
Kannst noch das einfügen (Auszug aus meinem Code mit DBGrid):

Code: Alles auswählen

        if gdRowHighlight in aState then
          TDbGrid(Sender).Canvas.Brush.Color :=
            ColorToRGB(TDbGrid(Sender).Canvas.Brush.Color) xor $1F1F1F;
wenn die Options.dgRowHighlight TRUE ist.
EleLa - Elektronik Lagerverwaltung - www.elela.de

DonMigos
Beiträge: 52
Registriert: Mi 15. Mai 2013, 21:21
OS, Lazarus, FPC: Win7 (L 1.0.8 FPC 2.6.2)
CPU-Target: 32Bit

Re: StringGrid und DrawCell

Beitrag von DonMigos »

Danke für die Antworten !
MmVisual hat geschrieben:Mache das:

Code: Alles auswählen

if (gdSelected in aState) or (gdFocused in aState) then 
Kannst noch das einfügen (Auszug aus meinem Code mit DBGrid):

Code: Alles auswählen

        if gdRowHighlight in aState then
          TDbGrid(Sender).Canvas.Brush.Color :=
            ColorToRGB(TDbGrid(Sender).Canvas.Brush.Color) xor $1F1F1F;
wenn die Options.dgRowHighlight TRUE ist.

Code: Alles auswählen

if (gdSelected in aState) or (gdFocused in aState) then 
Hatte ich schon, hilft nichts.

gdRowHighlight gibt es bei StringGrid nicht.
theo hat geschrieben:Naja, ein Feld ist halt immer ausgewählt. Schlimm?
Sieht halt echt blöd aus ...
Und unter Delphi hatte es halt auch geklappt...

Soner
Beiträge: 734
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: StringGrid und DrawCell

Beitrag von Soner »

DonMigos hat geschrieben:Ein kleines Problem bekomme ich noch nicht weg, es wird am Anfang immer die erste Zelle im Grid mit der Farbe überzeichnet, welche für die Selektion gedacht ist.
...
Dast ist ja so gewollt, sonst weiß ja der Benutzer nicht in welche Zelle er etwas eingibt. Wenn du das ändern willst dann füge doch Bedingung hinzu, so etwas:
if DateiGeladen and ((gdSelected in AState) or (gdFocused in AState)) then ...

Wußtest du auch das alles was du machst StringGrid schon bietetet:
AlternateColor,
FocusedColor,
SelectedColor,
OnPrepareCanvas (Canvas.TextStyle für Textausrichtung),
...

Mehr gibt's hier:
http://wiki.freepascal.org/Grids_Reference_Page/de

Antworten