Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi TDBGrid/TJvDBGrid Highlighting direkt nach dem Einlesen (https://www.delphipraxis.net/215459-tdbgrid-tjvdbgrid-highlighting-direkt-nach-dem-einlesen.html)

Bodenseematze 8. Jul 2024 09:14


TDBGrid/TJvDBGrid Highlighting direkt nach dem Einlesen
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo,

ich verwende ein TJvDBGrid zur Darstellung von Detail-Datensätzen, wobei eine Spalte mit langem Bezeichnungstext in der Tabelle nie vollständig sichtbar ist und deshalb der Text der aktuell selektierten Zeile zusätzlich noch auf der Maske in einem TDBMemo dargestellt wird.
Das ganze basiert auf TDataSource / TQuery-Kombinationen (BDE - ja, ich weiß :wink:) und Delphi 7.

Nachdem der Hauptdatensatz und die Detail-Datensätze eingelesen sind, wird auf den letzten Detaildatensatz positioniert.
Das Memo-Feld zeigt dann auch richtigerweise den vollständigen Text des letzten Satzes an.

Aber leider ist im Grid die (aktive) Zeile nicht markiert / hervorgehoben, sondern komischerweise in einer anderen Zeile eine Spalte Anhang 56983

Erst wenn ich in eine Zeile im Grid klicke, wird diese korrekt hervorgehoben:
Anhang 56984

BTW, das klicken ins Grid ohne eine Zeile zu "erwischen", verändert nichts - die Hervorhebung bleibt falsch.

Programmtechnisch habe ich auch schon versucht, den Fokus zu setzen - ohne Erfolg (vielleicht ist das auch nicht zum richtigen Zeitpunkt gemacht worden...)
(wurde im OnAfterScroll des Detail-Queries gemacht)

Das Grid hat MultiSelect und die folgenden Optionen gesetzt: dgEditing, dgTitles, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit, dgMultiSelect
Außerdem ist eine AlternateRowColor gesetzt, damit jede zweite Zeile anders hinterlegt ist.
AutoSizeRows ist gesetzt

Im OnDrawColumnCell-Handler des Grids werden:
- Spalten, deren Wert sich ggü. der Datenbank geändert hat, rot markiert
(bzw. alle Spalten einer Zeile, wenn die Zeile neu ist)
- wenn der TGridDrawState gdSelected enthält, wird die Font-Farbe auf clHighlightText gesetzt
(das ist standardmäßig nicht so und m.E. ein Bug)
- bei schreibgeschützten Spalten wird die Hintergrundfarbe "aufgehellt"
- die Spalten (bis auf die o.a. Bezeichnungsspalte) werden ggf. in der Breite angepasst, damit der Inhalt komplett sichtbar ist

Wie bekomme ich es hin, dass nach dem Einlesen der Datensätze die Zeile des aktiven Datensatzes hervorgehoben wird?
(die Option dgAlwaysShowSelection habe ich auch schon testweise gesetzt - hat nichts verändert)

Hier noch der relevante Code aus dem OnDrawColumnCell-Event des Grids:
Delphi-Quellcode:
procedure  TMyClass.dbGridDetailDrawColumnCell(
                                    sender_              : TObject;
                                    const rect_          : TRect;
                                    iDataCol_            : Integer;
                                    col_                 : TColumn;
                                    drawState_           : TGridDrawState );
var
   fld              : TField;
   bHandled         : Boolean;
   iWidthTitle      : Integer;
   iWidth           : Integer;
   fontContent      : TFont;
   iRowCount        : Integer;
   myGrid           : THackedDBGrid;
begin
   if ( NOT Assigned(col_) ) then begin
      inherited;

      Exit;
   end;

   bHandled               := false;
   fld                    := col_.Field;
   myGrid                 := THackedDBGrid( dbGridDetail );

   if ( NOT fld.Calculated ) then begin
      bHandled            := true;
      if ( IsModified(fld) or
           (qryTail.CachedUpdates and ( qryTail.UpdateStatus() = usInserted )) ) then begin
         myGrid.Canvas.Font.Color := clRed;
      end
      else begin
         myGrid.Canvas.Font.Color := clWindowText;
      end;
   end;

   if ( (gdSelected in drawState_) ) then begin
      if ( myGrid.Canvas.Font.Color <> clHighlightText ) then begin
         bHandled         := true;

         // die Fontfarbe "korrekt" setzen:
         myGrid.Canvas.Font.Color  := clHighlightText;
      end;
   end
   else
   if ( col_.ReadOnly ) then begin
      // Hintergrundfarbe etwas "aufhellen":
      bHandled            := true;
      if ( NOT Odd(myGrid.CurrentDrawRow) ) then begin
         myGrid.Canvas.Brush.Color
                           := Unit_HelperMisc.ColorLighterOrDarker(
                                    myGrid.AlternateRowColor,
                                    +10 );
      end
      else begin
         myGrid.Canvas.Brush.Color
                           := Unit_HelperMisc.ColorLighterOrDarker(
                                    myGrid.Color,
                                    +10 );
      end;
   end;

   // ggf. Größenanpassung (ausser bei der "Text"-Spalte, die wird am Schluss
   //   dann in dbGridTailColsResize behandelt):
   if ( NOT _bGridTailColsWidthSet ) then begin
      if ( NOT AnsiSameText(col_.FieldName, 'Text') ) then begin
         iWidthTitle      := 0;
         if ( dgTitles in myGrid.Options ) then begin
            // der Titel hat evtl. einen anderen Font
            // --> umstellen:
            fontContent   := myGrid.Canvas.Font;
            myGrid.Canvas.Font := myGrid.TitleFont;
            iWidthTitle   := myGrid.Canvas.TextExtent(
                                       col_.Title.Caption + ' \/' ).cx;
            myGrid.Canvas.Font  := fontContent;
         end;
         iWidth           := myGrid.Canvas.TextExtent(
                                       fld.DisplayText ).cx;
         if ( (myGrid.MinColumnWidth > 0) and
              (iWidth < myGrid.MinColumnWidth) ) then begin
            iWidth        := myGrid.MinColumnWidth;
         end;

         if ( (myGrid.MaxColumnWidth > 0) and
              (iWidth > myGrid.MaxColumnWidth) ) then begin
            iWidth        := myGrid.MaxColumnWidth;
         end;

         if ( iWidthTitle > iWidth ) then begin
            iWidth        := iWidthTitle;
         end;
         Inc( iWidth, 5 );

         if ( iWidth <> col_.Width ) then begin
            col_.Width    := iWidth;
         end;
      end; // if ( NOT AnsiSameText(col_.FieldName, 'Text') ) then

      // letzte Spalte
      // --> Breite der Text-Spalte auch setzen:
      if ( iDataCol_ = (myGrid.Columns.Count - 1) ) then begin
         dbGridTailSetColTextWidth();

         // letzte Zeile:
         if ( qryTailPos_Nr.AsInteger = _lstPosNr.Max ) then begin
            _bGridTailColsWidthSet := true;
         end;
      end;
   end; // if ( NOT _bGridTailColsWidthSet ) then

{$IFDEF notdef} // das hebt die falsche Zeile hervor:
   // aktuell ausgewählte Zeile auch entspr. markieren:
   if ( (myGrid.Row = ( myGrid.DataLink.ActiveRecord + 1 )) ) then begin
 //or
//        (gdFocused in drawState_) or
//        (gdSelected in drawState_) ) then begin
      myGrid.Canvas.Brush.Color := clHighLight;
      myGrid.Canvas.Font.Color  := clHighLightText;
      bHandled            := true;
   end;
{$ENDIF notdef}

   if ( bHandled ) then begin
      dbGridTail.DefaultDrawColumnCell( rect_, iDataCol_, col_, drawState_ );
   end;

   inherited;
end;

himitsu 8. Jul 2024 09:29

AW: TDBGrid/TJvDBGrid Highlighting direkt nach dem Einlesen
 
Ein Grid.Repaint oder Grid.Refresh nach dem Laden versucht?



Sicher, dass ActiveRecord genau mit der Row übereinstimmt?

myGrid.DataLink.ActiveRecord dürfte doch dem myGrid.DataLink.DataSet.RecNo aka qryTail.RecNo entsprechen und demnach bei 1 beginnen zu zählen.

Die Row beginnen oft bei 0 ... k.A. ob hier beim JV die TitelRow/FoxedRow mitgezählt wird.

Bodenseematze 8. Jul 2024 10:33

AW: TDBGrid/TJvDBGrid Highlighting direkt nach dem Einlesen
 
In meinem Test habe ich sieben Detail-Dateinsätze
Wenn ich mir in OnDrawColumnCell den ActiveRecord und die Grid.Row protokolliere sehe ich,
    1. OnDrawColumnCell wird schön für jede meiner Positionsnummern und jede Spalte aufgerufen;
    2. aber komischerweise gibt es zwei komplette Durchläufe...
  1. im ersten Durchlauf ist bei der ersten Spalte der letzten Zeile drawState_ = [Selected]
    1. auch ActiveRecord zählt zuerst schön hoch von 0..6
    2. dann kommt zum Schluss noch ein Aufruf für die Spalte 0 mit ActiveRecord=5, hier ist dann drawState_ = [Selected, Focused]
  2. Grid.Row ist auch seltsam - beim ersten Durchlauf zuerst = 1 (ActiveRecord 0..4) dann immer = 6 (ActiveRecord 5..6);
    im zweiten Durchlauf ist es immer 6 (auch beim letzten Aufruf - s.a. 2b)

qryTail.RecNo ist bei mir übrigens immer -1 - also nicht zu gebrauchen (liegt wohl am ODBC-Treiber von MS).


Zitat:

Zitat von himitsu (Beitrag 1538653)
Ein Grid.Repaint oder Grid.Refresh nach dem Laden versucht?

Die Schwierigkeit hierbei ist - wann (d.h. in welchem Event) ist "nach dem Laden"?

Delphi.Narium 8. Jul 2024 17:10

AW: TDBGrid/TJvDBGrid Highlighting direkt nach dem Einlesen
 
Nimm am Ende mal das inherited raus, das darf, nach meiner Erfahrung mit Delphi 7 und TJVDBGrid, nur dann aufgerufen werden, wenn Du im dbGridDetailDrawColumnCell nichts selbst machst, also nur für die Zellen aufgerufen werden, für die es keine von Dir implementierte "Sonderbehandlung" gibt.

Eventuell ergänzt Du die Methode aber am Ende auch um einen Elsezweig:
Delphi-Quellcode:
   if ( bHandled ) then begin
      dbGridTail.DefaultDrawColumnCell( rect_, iDataCol_, col_, drawState_ );
   end else begin
      inherited;
   end;

Bodenseematze 9. Jul 2024 07:05

AW: TDBGrid/TJvDBGrid Highlighting direkt nach dem Einlesen
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1538668)
Delphi-Quellcode:
   if ( bHandled ) then begin
      dbGridTail.DefaultDrawColumnCell( rect_, iDataCol_, col_, drawState_ );
   end else begin
      inherited;
   end;

Genau so war es ursprünglich - bevor ich mit den "Versuchen" angefangen hatte :lol:

Was übrigens auch noch komisch ist (Bug in JvDBGrid?): wenn das Grid den Fokus nicht hat, und ich das erste Mal in's Grid auf eine Zeile klicke, wird immer die falsche Zeile markiert (eine Zeile tiefer, als ich klicke).
Das passiert aber nur beim ersten Mal - danach passt's dann (auch wenn ich den Fokus wieder woanders hin setze und dann wieder zurück ins Grid)...

Delphi.Narium 9. Jul 2024 16:53

AW: TDBGrid/TJvDBGrid Highlighting direkt nach dem Einlesen
 
Der Fehler muss irgendwo anders liegen :-(

Nagut, kann ich jetzt nur so behaupten aber nicht begründen.

Habe einige in Delphi 7 geschriebene Programme, in denen das JVDBGrid genutzt wird, in denen die Implementierung in der Prozedur zu OnDrawColumnCell analog zu Deiner Implementierung erfolgt und die am Ende immer per Case oder sonstiger Abfrage entweder DefaultDrawColumnCell oder inherited aufrufen. Und bei mir treten keine Probleme auf, es wird immer auf Anhieb die richtige Zeile ausgewählt, das Grid hat nur in den seltensten Fällen den Focus, es sei denn per Tab, HotHey oder Mausklick wird es ausgewählt.

Breakpoint auf die erste Zeile von dbGridDetailDrawColumnCell und dann per Debugger. Wann wird dbGridDetailDrawColumnCell aufgerufen? Eventuell vor dem per Klick veranlassten Satzwechsel, aber danach nicht mehr. Ein bisserl erscheint mir Deine Fehlerbeschreibung so, als ob da die Reihenfolge der Verarbeitungsschritte nicht so ganz den Erwartungen entspricht. Nur aus der Ferne kann man da lediglich mutmaßen. Ich weiß nur, dass ich beim ersten Programm, bei dem ich ein Prozudur analog zu Deinem dbGridDetailDrawColumnCell implementiert habe, sehr lange gebraucht habe, um eine funktionierende Variante zu finden. Da das aber schon über 10 Jahre her ist, kann ich nicht mehr sagen, wo genau der Knackpunkt lag.

Die von mir genutzte Version von TJVDBrid ist vom 07.09.2011, also nicht so unbedingt die Neueste.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:38 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz