How to fix owner draw anomaly in DBGrid?
Asked Answered
I

1

0

Continuing with the project started in:

How to auto fit/scale DBGrid's (or other similar) columns widths according to its contents?

I used the @alzaimar answer to auto fit the columns according to their content width, but he showed me how to increase the width, but not how to decrease, so I complemented the code as shown above:

procedure TRecordsBrowserFrameBase.JvDBGrid2DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  h, p, g, r, w, t : Integer;
const
  colSpc = 10;
begin
{ ajusta as colunas de uma grade de acordo com o conteúdo das células }
  h := Column.DropDownRows;
  p := (Sender as TJvDBGrid).CurrentDrawRow;
  g := Column.Width;
  r := (Sender as TJvDBGrid).VisibleRowCount;
  w := colSpc + (Sender as TJvDBGrid).Canvas.TextExtent(Column.Field.DisplayText).cx;
  t := colSpc + (Sender as TJvDBGrid).Canvas.TextExtent(Column.Title.Caption).cx;
{$WARNINGS OFF}
  // increase column width if needed
  if (w > g) then Column.Width := w;
  if (g < t) then Column.Width := t;
  if (p < r) and (h < w) then Column.DropDownRows := w;
  // decrease column size if needed (10th line)
  if (p = r) then
  begin
    h := Column.DropDownRows;
    g := Column.Width;
    if (h > t) and (h < g) then Column.Width := Column.DropDownRows;
    Column.DropDownRows := 0;
  end;
{$WARNINGS ON}
end;

So, now when I scroll with the down arrow key, the selected row color does not always is in the correct position as you can see in this picture:

enter image description here

What I am doing wrong?

Investigate answered 8/11, 2012 at 20:44 Comment(14)
The use of the DropDownRows is an substitute for the Tag property that doesn't exist on the TColumn object and I need to use it to keep the higher width inside the visible rows, once the column's width keeps the global higher size.Investigate
Your selection - row indicator anomaly isn't due to this code.Nakitanalani
You have zero code in what you posted that actually draws anything, so the row indicator problem isn't there. (You measure text width and set the new width, but you don't actually draw to the grid.)Hyperion
the problem started when i decided to downsize the width when the text on the column gets smaller. If i remove above the 10th line, the pointer and the blue line synchronize.Investigate
Can you make this a stand-alone question? Anyway, AFAIU from your acceptance on your other question, you are setting column widths while the columns are drawing. Not a good idea, setting widths should cause in-turn columns to be drawn. I'd suggest to try employing Cesar's answer there and see if you have the same problem.Reception
@EASI 10th line from where? Starting with procedure or begin, included or not? Counting the comment lines? Maybe you point it out inside the code and it will be clear to everyone and not only to you ;o)Zeuxis
@Sir - I thought it was the 10th line in the grid. :oReception
@SertacAkyuz you might be right :o)Zeuxis
@EASI, learn to use meaningful variable names, your code is difficult to read and understand because your variables doesn't help. if (w > g) ??? what that means? width > what??, I know I can read the full code to try to understand, but I dislike to do so.Anastase
@Anastase "w" is the text Width and "g" is the current width of the column. "r" is the number of visible rows and "t" is the width of the title text.Investigate
I am not used to put those names on variables. But I am still testing this code, and when it's done I will correct that.Investigate
@EASI, calling the variables width and currWidth or something like that will help not only you but anyone else to read, understand and maybe improve the code.Anastase
i tried to proceed out of the event but i get the same problemInvestigate
I haven't worked with this type of grid, but I would assume that setting the width while drawing causes the grid drawing routine, especially drawing the focused row, to mess up. As a workaround, save the width in a separate array (one element per column) and set a flag in your code when you have to update the width. In the idle routine of the form, check the flag and if it is set, set the width of the columns to the updated values. Another approach would be to start a timer to redraw, but this is really dirty and would be the last choice prior to giving up.Snowstorm
I
1

This solution makes all columns expand or shrink according to it's contents, without care if there has to be scroll bars or not, and fix the selected cell drawing malfunction and the the record pointer malfunction.

type
  TColumnAutoAdjust = record {Save the information responsible for setting column widths in the grid}
    Field: String;           {Field name whose information is being stored}
    Registered: Boolean;     {Indicates whether the size of this column already registered}
    Updated: Boolean;        {Indicates the actual size of the column was updated}
    LastWidth: Integer;      {Width indicates the final text of a record of a row column}
    CurrWidth: Integer;      {Indicates the current size and column width}
    Reverter: Integer;       {Indicates the greatest width recorded but that is less than the current}
    Scrolls: Integer;        {Indicates the amount of scrolls present after one width adjustment}
    RecNo: Integer;          {Indicates which was the record in the table which increased the width of colune}
  end;

var { inside the forms private }
  gdCols: array of TColumnAutoAdjust; { vetor de ajuste de largura de cada coluna na grade de resultado }
  RegisteredCols: Integer; { quantas colunas já foram registradas no controle de ajuste }
  gdVisibleRows: Integer; { quantas linhas de cadastros estão visíveis da grade de resultado }
  gdVisibleCols: Integer; { quantas colunas de cadastros estão visíveis da grade de resultado }

{ before showing the grid }  
    RegisteredCols := ResultGrid.Columns.Count;
    SetLength(gdCols, RegisteredCols); { determina o tamanho da vetor de controle de colunas }
    { libera a lista }
    ResultGrid.Align := alClient;
    for i := 0 to RegisteredCols -1 do { inicializando a largura das colunas no tamanho do título de cada }
    begin
      gdCols[i].Field := ResultGrid.Columns[i].FieldName;
      ResultGrid.Columns[i].Width := ResultGrid.Canvas.TextExtent(ResultGrid.Columns[i].Title.Caption).cx;
      ResultGrid.Columns[i].Alignment := taLeftJustify;
      ResultGrid.Columns[i].Title.Alignment := taLeftJustify;
    end;
    BrowserQuery.Open;
    ResultGrid.Show;
    for i := 0 to gdVisibleRows do
    begin
      BrowserQuery.Next;
      ResultGrid.Refresh;
    end;
    for i := 0 to gdVisibleRows do
    begin
      BrowserQuery.Prior;
      ResultGrid.Refresh;
    end;
    BrowserQuery.First;
    ResultGrid.SetFocus;
  end

{ after dataset scroll}      
procedure TRecordsBrowserFrameBase.BrowserQueryAfterScroll(DataSet: TDataSet);
var
  i, TitleWidth: Integer;
  mayAdjustAgain: Boolean; {  }
begin
{ ajusta as colunas da grade de resultado a cada movimento da tabela de resultado }
  mayAdjustAgain := False;
  for i := 0 to RegisteredCols -1 do
  begin
    if not gdCols[i].Updated then
    begin
      ResultGrid.Columns[i].Width := gdCols[i].CurrWidth;
      gdCols[i].Scrolls := 0;
      gdCols[i].Updated := True;
    end
    else
    begin
      Inc(gdCols[i].Scrolls);
      if (DataSet.RecNo > gdCols[i].RecNo + gdVisibleRows) or (DataSet.RecNo < gdCols[i].RecNo - gdVisibleRows) then
      begin
        TitleWidth := MaxColSpacing + ResultGrid.Canvas.TextExtent(ResultGrid.Columns[i].Title.Caption).cx;
        gdCols[i].LastWidth := gdCols[i].CurrWidth;
        gdCols[i].CurrWidth := IFX(gdCols[i].Reverter > TitleWidth, gdCols[i].Reverter, TitleWidth);
        gdCols[i].Reverter := IFX(gdCols[i].Reverter > TitleWidth, TitleWidth, 0);
        gdCols[i].Updated := False;
        mayAdjustAgain := True;
      end;
    end;
  end;
  if mayAdjustAgain then
  begin
    ResultGrid.Refresh;
    BrowserQueryAfterScroll(DataSet);
  end;
end;

{ on draw column cell }

procedure TRecordsBrowserFrameBase.GridColumnWidthAdjust(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  ColWidth, TextWidth, TitleWidth: Integer;
begin
{ ajusta a capitalização do texto das células }
  (Sender as TJvDBGrid).Canvas.Pen.Color := clWhite;
  (Sender as TJvDBGrid).Canvas.Rectangle(Rect);
  (Sender as TJvDBGrid).Canvas.TextOut(Rect.Left+2, Rect.Top+2, NameCase(Column.Field.DisplayText));
{ ajusta as colunas de uma grade de acordo com o conteúdo das células }
  gdVisibleRows := (Sender as TJvDBGrid).VisibleRowCount;
  gdVisibleCols := (Sender as TJvDBGrid).VisibleColCount;
  TitleWidth := MaxColSpacing + (Sender as TJvDBGrid).Canvas.TextExtent(Column.Title.Caption).cx;
  TextWidth := MaxColSpacing + (Sender as TJvDBGrid).Canvas.TextExtent(NameCase(Column.Field.DisplayText)).cx;
  ColWidth := Column.Width;
  {$WARNINGS OFF}
  if (TextWidth > gdCols[DataCol].Reverter) and (TextWidth < ColWidth) then gdCols[DataCol].Reverter := TextWidth;
  if (TextWidth > ColWidth) then { texto da célula é mais largo que a coluna }
  begin
    gdCols[DataCol].Registered := True;
    gdCols[DataCol].LastWidth := ColWidth;
    gdCols[DataCol].CurrWidth := TextWidth;
    gdCols[DataCol].Updated := False;
    gdCols[DataCol].RecNo := BrowserQuery.RecNo;
    gdCols[DataCol].Reverter := TitleWidth;
    Exit;
  end;
  if (ColWidth < TitleWidth) then { texto da célula é menor que o título da coluna }
  begin
    gdCols[DataCol].Registered := True;
    gdCols[DataCol].LastWidth := ColWidth;
    gdCols[DataCol].CurrWidth := TitleWidth;
    gdCols[DataCol].Updated := False;
    gdCols[DataCol].Reverter := TitleWidth;
    Exit;
  end;
{$WARNINGS ON}
end;
Investigate answered 19/11, 2012 at 22:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.