Delphi-PRAXiS
Seite 5 von 5   « Erste     345   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TVirtualStringTree AutoFitColumns erste Spalte wird nicht angepasst (https://www.delphipraxis.net/192260-tvirtualstringtree-autofitcolumns-erste-spalte-wird-nicht-angepasst.html)

madas 6. Apr 2017 12:34

AW: TVirtualStringTree AutoFitColumns erste Spalte wird nicht angepasst
 
Zitat:

Zitat von TUX_der_Pinguin (Beitrag 1366615)
Zitat:

Zitat von madas (Beitrag 1366613)
Tja da hat wohl jemand das "^" beim Zugriff auf Data vergessen.

alt:

Delphi-Quellcode:
Node := vstTable.FocusedNode;
  if Assigned(Node) then
  begin
    Data := vstTable.GetNodeData(Node);
    if Assigned(Data) then
    begin
      Data.Name := Data.Name + 'xyz 12345';
      Data.Desc := Data.Desc + 'xyz 12345';
    end;
  end;
so wie es muss:

Delphi-Quellcode:
Node := vstTable.FocusedNode;
  if Assigned(Node) then
  begin
    Data := vstTable.GetNodeData(Node);
    if Assigned(Data) then
    begin
      Data^.Name := Data^.Name + 'xyz 12345';
      Data^.Desc := Data^.Desc + 'xyz 12345';
    end;
  end;
Beim OnGetText genau so. Usw.

Was heißt vergessen, es funktionierte bisher auch gut ohne. Aber auch mit "^" ändert sich nichts am ursprünglichen Problem, das die erste Spalte nicht angepasst wird wenn ich AutoFitColumns aufrufe.

Ähm sorry Irrtum vom Amt. War irgendein Cache Effekt.
Mache bei den MiscOptions mal toGridExtensions rein, dann sollte es funzen.

TUX_der_Pinguin 6. Apr 2017 12:35

AW: TVirtualStringTree AutoFitColumns erste Spalte wird nicht angepasst
 
Zitat:

Zitat von Codehunter (Beitrag 1366629)
@TUX_der_Pinguin: Mal dumm gefragt: Verwendest du den VST als Tree oder als Grid? Sprich, brauchst du das ganze Aufklapp-Gedönse überhaupt? Denn wenn nicht, setzt du einfach Header.MainColumn auf 1 und der Fehler ist umgangen.

Jetzt kann ich zumindest das Problem nachvollziehen. Hinzu kommt, die drei "Abkürzungspünktchen" werden auch nicht korrekt angezeigt wenn man die Spalte 0 danach manuell verkleinert. Erst nach einem Invalidate (implizit durch Fokuswechsel) wird der Node richtig initialisiert. Das spräche ja dafür, dass der VST doch irgendwas intern puffert. Sehr seltsam.

Besonders deutlich wird das Problem, wenn man TreeOptions.StringOptions.toShowStaticText setzt. Dann überlappen sich in Spalte 0 sogar die Texte. Das ist Mumpitz. Scheint also ein Käferchen im VST zu sein. :-(

Ich würde vorerst bei meiner Vermutung bleiben, dass da irgendwo im VST eine hartcodierte MainColumn = 0 verblieben ist.

Ich verwende in den meisten Fällen die Komponente nur als Grid, aber einfach Header.MainColumn auf '1' zu setzten geht nicht wenn man wie in meinem Projekt teilweise nur eine Spalte hat. Naja und da die Lösung mit InvalidateNode() ja funktioniert, belasse ich es mit der Lösung.

Und das habe ich ja die ganze Zeit auch gemeint da das Verhalten so merkwürdig ist das ich da auch auf einen Bug schließe und nicht auf ein gewolltes Verhalten. Ich hatte das auch so als Bug Report bei GitHub eingestellt.

TUX_der_Pinguin 6. Apr 2017 12:36

AW: TVirtualStringTree AutoFitColumns erste Spalte wird nicht angepasst
 
Zitat:

Zitat von madas (Beitrag 1366631)
Mache bei den MiscOptions mal toGridExtensions rein, dann sollte es funzen.

Nein auch mit der Option ändert sich nichts.

madas 6. Apr 2017 12:48

AW: TVirtualStringTree AutoFitColumns erste Spalte wird nicht angepasst
 
Bitte sehr. Option toGridExtensions hinzugefügt und die "^" eingebaut. Mehr nicht. Läuft, falls man einen Node selektiert hat. ;)

Delphi-Quellcode:
object Form2: TForm2
  Left = 0
  Top = 0
  Caption = 'Form2'
  ClientHeight = 489
  ClientWidth = 730
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object vstTable: TVirtualStringTree
    Left = 112
    Top = 88
    Width = 505
    Height = 345
    Header.AutoSizeIndex = 0
    Header.Font.Charset = DEFAULT_CHARSET
    Header.Font.Color = clWindowText
    Header.Font.Height = -11
    Header.Font.Name = 'Tahoma'
    Header.Font.Style = []
    Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
    TabOrder = 0
    TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick]
    TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages]
    TreeOptions.SelectionOptions = [toFullRowSelect]
    OnGetText = vstTableGetText
    Columns = <
      item
        Position = 0
        WideText = 'Name'
      end
      item
        Position = 1
        WideText = 'Description'
      end>
  end
  object Button1: TButton
    Left = 144
    Top = 57
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 1
    OnClick = Button1Click
  end
end
Delphi-Quellcode:
unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, Vcl.StdCtrls;

type
  TMyDataSet = record
    Name: String;
    Desc: String;
  end;
  PMyDataSet = ^TMyDataSet;

type
  TForm2 = class(TForm)
    vstTable: TVirtualStringTree;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure vstTableGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var
  Node: PVirtualNode;
  Data: PMyDataSet;
 
begin
  vstTable.BeginUpdate;

  Node := vstTable.FocusedNode;
  if Assigned(Node) then
  begin
    Data := vstTable.GetNodeData(Node);
    if Assigned(Data) then
    begin
      Data^.Name := Data^.Name + 'xyz 12345';
      Data^.Desc := Data^.Desc + 'xyz 12345';
    end;
  end;

  vstTable.EndUpdate;
  vstTable.Header.AutoFitColumns(False, smaAllColumns);
end;

procedure TForm2.FormCreate(Sender: TObject);
var
  Node: PVirtualNode;
  Data: PMyDataSet;
  Index: Integer;
 
begin

  vstTable.NodeDataSize := SizeOf(TMyDataSet);
  vstTable.BeginUpdate;

  for Index := 1 to 10 do
  begin
    Node := vstTable.AddChild(nil);
    Data := vstTable.GetNodeData(Node);
    if Assigned(Data) then
    begin
      Data^.Name := IntToStr(Index)+'. Bla bla';
      Data^.Desc := 'Bla bla bla bla';
    end;
  end;

  vstTable.EndUpdate;

  vstTable.Header.AutoFitColumns(False, smaAllColumns);
 
end;

procedure TForm2.vstTableGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  Data: PMyDataSet;
 
begin
  Data := vstTable.GetNodeData(Node);
  if Assigned(Data) then
  begin
    case Column of
      0: CellText := Data^.Name;
      1: CellText := Data^.Desc;
    end;
  end;
 
end;

end.

Codehunter 6. Apr 2017 12:58

AW: TVirtualStringTree AutoFitColumns erste Spalte wird nicht angepasst
 
Zitat:

Zitat von madas (Beitrag 1366636)
Bitte sehr. Option toGridExtensions hinzugefügt und die "^" eingebaut. Mehr nicht. Läuft, falls man einen Node selektiert hat. ;)

Nix läuft. Dass das mit dem selektierten Node funktioniert ist eher ein Seiteneffekt, aber keine Lösung.

Ich denke aber ich bin des Rätsels Lösung schon sehr sehr nahe. In TCustomVirtualStringTree.DoGetNodeWidth:
Delphi-Quellcode:
    if Column = FHeader.MainColumn then
    begin
      // Primary column or no columns.
      Data := InternalData(Node); // <-- Magic Wunderding !!!
      if Assigned(Data) then
      begin
        Result := Data^;
        if Result = 0 then
        begin
          Data^ := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]);
          Result := Data^;
        end;
      end
      else
        Result := 0;
    end
Der Schweinehund puffert doch die Textbreite tatsächlich! Wahrscheinlich aus Performancegründen, um eben nicht für jede einzelne Zelle die Textbreite über den DeviceContext berechnen zu müssen. Und hier kommt auch die Erklärung, warum es mit einem InvalidateNode funktioniert:
Delphi-Quellcode:
function TCustomVirtualStringTree.InvalidateNode(Node: PVirtualNode): TRect;

var
  Data: PInteger;

begin
  Result := inherited InvalidateNode(Node);
  // Achtung !!!  Hier des Rätsels Lösung:
  // Reset node width so changed text attributes are applied correctly.
  if Assigned(Node) then
  begin
    Data := InternalData(Node);
    if Assigned(Data) then
      Data^ := 0; // !!! InternalData wird auf 0 gesetzt, weshalb GetNodeWidth dann gezwungen ist neu zu berechnen.
    // Reset height measured flag too to cause a re-issue of the OnMeasureItem event.
    Exclude(Node.States, vsHeightMeasured);
  end;
end;
So: Rätsel gelöst! Ich lag falsch, der VST puffert doch die Textbreite. Daher ist die einzig richtige Lösung, ein InvalidateNode zu machen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:01 Uhr.
Seite 5 von 5   « Erste     345   

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