virtualTreeView als Grid [Gelöst]

Rund um die LCL und andere Komponenten
Antworten
UGerd
Lazarusforum e. V.
Beiträge: 18
Registriert: Fr 4. Mär 2011, 17:00
OS, Lazarus, FPC: Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hamburg

virtualTreeView als Grid [Gelöst]

Beitrag von UGerd »

Lazarus 1.2.6 r46529 FPC 2.6.4 i386-win32-win32/win64
virtual TreeView Revision: 3831

Hallo,
ich möchte VirtualTreeView wie Stringrid verwenden, also auch mit Tab durch die Felder navigieren.
Das klappt wie erwartet, es sei den, ich verwende F2 um zu editieren.
Nun wandert der Focus nach dem Tab in die nächste Reihe, statt ins nächste Feld und ein System-Ton erklingt.
Was mache ich falsch?

Code: Alles auswählen

unit fmain;
 
{$mode objfpc}{$H+}
 
interface
 
uses
      Classes, SysUtils, FileUtil, VirtualTrees, Forms, Controls, Graphics,
			Dialogs, StdCtrls;
 
type
			{ TForm1 }
 
      TForm1 = class(TForm)
						Btn: TButton;
						VST: TVirtualStringTree;
						procedure BtnClick(Sender: TObject);
      private
            { private declarations }
      public
            { public declarations }
      end;
 
var
      Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.BtnClick(Sender: TObject);
var
  Col: TVirtualTreeColumn;
  i: Integer;
begin
 
   VST.WantTabs:= true;
   for i:= 0 to 10 do
   VST.AddChild(nil);
 
  with VST.TreeOptions do
  begin
    MiscOptions:= MiscOptions + [toGridExtensions, toEditable];
    SelectionOptions:= SelectionOptions + [toExtendedFocus];
  end;
 
  with VST.Header do
    Options:= Options + [hoVisible];
 
  with VST.Header.Columns do
  begin
    clear;
    Col:= Add;
    Col.Text:= 'MainColum';
    Col.Options:= Col.Options - [coAllowFocus, coEditable];
    Col.Width:= 100;
 
    For i:= 1 to 3 do
    begin
      Col:= Add;
      Col.Text:= 'Column ' + IntToStr(i);
      Col.Options:= Col.Options + [coAllowFocus, coEditable];
      Col.Width:= 100;
    end;
 
  end;
 
end;
 
end.
Zuletzt geändert von UGerd am Mo 15. Dez 2014, 22:58, insgesamt 2-mal geändert.

wp_xyz
Beiträge: 5050
Registriert: Fr 8. Apr 2011, 09:01

Re: virtualTreeView als Grid

Beitrag von wp_xyz »

Hast du dir die Demos schon angesehen, die bei VT mit dabei sind? Tritt dein Problem dort auch auf? Welches VT-Package verwendest du? Leider gibt es im ccr zwei, das aktuellere ist das "-new".

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: virtualTreeView als Grid

Beitrag von Michl »

Hallo UGerd,

beim VirtualStringTree musst Du Dich, wie der Name schon sagt, selber um die Daten hinter den Einträgen kümmern! Ein Einsteigerbeispiel/Tutorial findest Du unter http://wiki.freepascal.org/VirtualTreev ... or_Lazarus. Wenn Du dieses durchgearbeitet hast und das Prinzip verstehst, wirst Du Dir selber die Frage beantworten können (zur Zeit sind keine TreeDaten zum editieren vorhanden!).

wp_xyz hat geschrieben:Hast du dir die Demos schon angesehen, die bei VT mit dabei sind? Tritt dein Problem dort auch auf? Welches VT-Package verwendest du? Leider gibt es im ccr zwei, das aktuellere ist das "-new".
lt. UGerd Revision 3831 - das ist der aktuelle Snapshot (von Dir der vorletzte Rev.-Eintrag 3712). Gibt es da zwei SVN-Versionen, an denen aktuell gearbeitet wird???

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

wp_xyz
Beiträge: 5050
Registriert: Fr 8. Apr 2011, 09:01

Re: virtualTreeView als Grid

Beitrag von wp_xyz »

@Michl: Im Nachhinein klar, an der Versionsnummer hätte ich es gesehen... Ich wollte nur sagen, dass es im CCR zwei Portierungen von VirtualTreeView gibt, von denen "virtualtreeview-new" die empfehlenswertere ist.

UGerd
Lazarusforum e. V.
Beiträge: 18
Registriert: Fr 4. Mär 2011, 17:00
OS, Lazarus, FPC: Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hamburg

Re: virtualTreeView als Grid

Beitrag von UGerd »

Ersteinmal: vielen Dank für die Antworten!

Um die Gegenfragen zu beantworten:

ich verwende folgende svn Version:
https://svn.code.sf.net/p/lazarus-ccr/s ... -new/trunk.

Das Ändern, Anzeigen und Speichern der Daten habe ich schon mit Hilfe des Tutorials erlernt, funktioniert auch wunderbar.
Ich habe dies in meinem Beispiel nur weggelassen, denn mein Problem wird auch so ersichtlich.

Ich habe mir auch schon eine Demo kompiliert:
C:\lazarus\components\VirtualTreeView_New\demos\advanced\Advanced.exe: Tree in Grid Simulation.
Hier stellt sich das "Tab-Problem" anders, aber ähnlich dar. Ohne F2 zum Editieren zu benutzen: alles wie erwartet. Nach dem Umschalten in den Editmodus muss ich aber 3X die Tab - Taste bemühen, um das editierte Feld zu verlassen. Ob der Demo-Autor hier einen mangelhaften Workaround verwendet? Ich weiß es nicht.

Dann habe ich eine Vorkompilierte (warscheinlich mit Delphi?) Demo-Version heruntergeladen, um auszuschließen, das das Problem bei Lazarus liegt. Liegt es nicht: Das gleiche Problem!

Im Bugtracker von Lazarus habe ich nach diesem Fehler gesucht und nichts gefunden.

Wegen meiner beschränkten Erfahrung beim Programmieren und mit VirtualTreeView fürchte ich, dass der Fehler bei mir liegt.
Und nun weiß ich nicht weiter.
Gruß
UGerd

wp_xyz
Beiträge: 5050
Registriert: Fr 8. Apr 2011, 09:01

Re: virtualTreeView als Grid

Beitrag von wp_xyz »

UGerd hat geschrieben: Ich habe mir auch schon eine Demo kompiliert:
C:\lazarus\components\VirtualTreeView_New\demos\advanced\Advanced.exe: Tree in Grid Simulation.
Hier stellt sich das "Tab-Problem" anders, aber ähnlich dar. Ohne F2 zum Editieren zu benutzen: alles wie erwartet. Nach dem Umschalten in den Editmodus muss ich aber 3X die Tab - Taste bemühen, um das editierte Feld zu verlassen. Ob der Demo-Autor hier einen mangelhaften Workaround verwendet? Ich weiß es nicht.
Ja, das beschriebene Verhalten mit TAB kann sehe ich auch. Das Problem wird sein, dass TAB mehrere Aufgaben hat: (1) um zwischen Controls zu wechseln, (2) bei VirtualTree, um in die nächste Spalte zu wechseln, (3) um ein Tabulator-Zeichen #9 in den editierten Node-Text einzufügen. Den Fall (1) kann man mit der Eigenschaft WantTabs ausschalten. Aber bei den anderen beiden fällt eine Variante unter den Tisch: Wie soll der Editor sonst entscheiden können, ob der gerade eingegebene Tabulator dafür gedacht ist, die Eingabe zu beenden und zum nächsten Feld zu gehen, anstatt ein Zeichen #9 in den Text einzufügen?

Aber wenn bei dir die eingegebenen Text keine Tabulatoren enthalten, könntest du dir eine eigene Editorklasse schreiben, die beim Empfang eines TAB zur nächsten Spalte geht. Du findest dazu Beispiele im Internet, evtl. sogar schon in dem erwähnten Demo Projekt. Vielleicht hilft dir auch schon wiki http://wiki.freepascal.org/VirtualTreev ... A_Combobox: Du musst nur dafür sorgen, dass in der Methode EditKeyDown von TStringEditLink der Tabulator abgefangen wird und das Editieren beendet; alles, was in dem Beispiel mit der Combobox zu tun hat, ist irrelevant - die Anpassung wird wahrscheinlich ein Dreizeiler...

UGerd
Lazarusforum e. V.
Beiträge: 18
Registriert: Fr 4. Mär 2011, 17:00
OS, Lazarus, FPC: Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hamburg

Re: virtualTreeView als Grid

Beitrag von UGerd »

@wp_xyz Vielen Dank für deinen wertvollen Beitrag! Er lässt Hoffnung keimen, am WE werde ich mich damit beschäftigen. Rückmeldung folgt!
Gruß
UGerd

wp_xyz
Beiträge: 5050
Registriert: Fr 8. Apr 2011, 09:01

Re: virtualTreeView als Grid

Beitrag von wp_xyz »

Weil mich das Thema interessiert, habe ich mir die VirtualTreeView-Editoren näher angesehen. So gut die Komponente ansonsten ist, hier hatte der Autor wohl nicht seinen besten Tag...

Der oben erwähnte "Dreizeiler" war etwas zu gut geschätzt: statt drei sind es fast 300 Zeilen geworden. Ich habe mir aus "VirtualTrees.pas" und der Demo-Unit "editors.pas" einen einfachen Zellen-Editor zusammengebastelt, der mit TAB so umgeht, so wie du dir das wahrscheinlich vorstellst. Im Edit-Modus (also nach Drücken von F2) wird nach Drücken von TAB der Eingabemodus beendet, der Text in den Datensatz geschrieben und die nächste Spalte in derselben Zeile fokussiert. Der Tree wechselt auch gleich wieder in den Eingabemodus. Am Ende einer Zeile wird das erste Feld der nächsten Zeile ausgewählt und zum Bearbeiten vorbereitet. Zusätzlich gibt es auch die Möglichkeit mit SHIFT+TAB zum vorigen Feld zu wechseln; falls man das erste Feld einer Zeile bearbeitet hat, geht es beim letzten der vorigen Zeile weiter.

Das Verhalten bei ENTER im Edit-Modus habe ich so realisiert, dass hier zum nächsten Feld entlang der Spalte gewechselt wird (bei SHIFT+ENTER zur vorigen Zeile). Allerdings bleibt hier die Eingabe bei der letzten (ersten) Zeile stehen.

Den Eingabemodus verlässt man mit ESC.

Zur Verwendung musst du die beigefügte Unit in die Uses-Zeile aufnehmen. Dann dem VirtualStringTree folgenden Event-Handler für OnCreateEditor zuweisen, damit der neue Editor verwendet wird (hier am Beispiel des GridForm im Advanced-Demo des VT-Package):

Code: Alles auswählen

 
procedure TGridForm.VST5CreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
  out EditLink: IVTEditLink);
begin
  EditLink := TVTStringEditLink.Create;
end;
 
Nicht vergessen, dass die eingegebenen Strings noch mit dem Ereignis OnNewText in die Daten geschrieben werden müssen, die im VirtualTree angezeigt werden. In dem AdvancedDemo (GridForm) geht das so:

Code: Alles auswählen

 
procedure TGridForm.VST5NewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; const NewText: String);
var
  Data: PGridData;
begin
  Data := Sender.GetNodeData(Node);
  if Column > 0 then
    Data.Value[Column-1] := NewText;
end;
 
Ich habe das alles mit der Trunk-Version von VirtualTreeView gemacht und hoffe, dass keine Änderungen zur Stable-Version betroffen sind. Ansonsten melde dich hier doch nochmals.

P.S.
Leider lässt mich die Forum-Software gerade nicht die Unit als Anhang hochladen, daher hier direkt im Posting:

Code: Alles auswählen

 
unit VTEditor;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  LCLType, LCLIntf, Messages, Classes, SysUtils, Graphics, Controls, Forms, StdCtrls, VirtualTrees;
 
type
  { TVTStringEditLink }
 
  TVTStringEditLink = class(TInterfacedObject, IVTEditLink)
  private
    FEdit: TEdit;              // Edit control as cell editor
    FTree: TVirtualStringTree; // A back reference to the tree calling.
    FNode: PVirtualNode;       // The node being edited.
    FColumn: Integer;          // The column of the node being edited.
  protected
    procedure EditExit(Sender: TObject);
    procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  public
    destructor Destroy; override;
    function BeginEdit: Boolean; stdcall;
    function CancelEdit: Boolean; stdcall;
    function EndEdit: Boolean; stdcall;
    function GetBounds: TRect; stdcall;
    function PrepareEdit(ATree: TBaseVirtualTree; ANode: PVirtualNode;
      AColumn: TColumnIndex): Boolean; stdcall;
    procedure ProcessMessage(var Message: TMessage); stdcall;
    procedure SetBounds(R: TRect); stdcall;
  end;
 
 
 
implementation
 
//----------------- TVTStringEditLink ------------------------------------------
 
destructor TVTStringEditLink.Destroy;
begin
  Application.ReleaseComponent(FEdit);
  inherited;
end;
 
//------------------------------------------------------------------------------
 
procedure TVTStringEditLink.EditExit(Sender: TObject);
begin
  FTree.EndEditNode;
end;
 
//------------------------------------------------------------------------------
 
type
  TVirtualStringTreeHack = class(TVirtualStringTree);
 
procedure TVTStringEditLink.EditKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
var
  node: PVirtualNode;
  col: TColumnIndex;
  GetStartColumn: function(ConsiderAllowFocus: Boolean = False): TColumnIndex of object;
  GetNextColumn: function(Column: TColumnIndex; ConsiderAllowFocus: Boolean = False): TColumnIndex of object;
  GetNextNode: TGetNextNodeProc;
begin
  case Key of
    VK_ESCAPE:
      begin
        FTree.CancelEditNode;
        Key := 0;
      end;
    VK_RETURN:
      begin
        FTree.InvalidateNode(FNode);
        if (ssShift in Shift) then
          node := FTree.GetPreviousVisible(FNode, True)
        else
          node := FTree.GetNextVisible(FNode, True);
        FTree.EndEditNode;
        if node <> nil then FTree.FocusedNode := node;
        Key := 0;
        if FTree.CanEdit(FTree.FocusedNode, FTree.FocusedColumn) then
          TVirtualStringTreeHack(FTree).DoEdit;
      end;
    VK_TAB:
      begin
        FTree.InvalidateNode(FNode);
        if ssShift in Shift then
        begin
          GetStartColumn := @FTree.Header.Columns.GetLastVisibleColumn;
          GetNextColumn := @FTree.Header.Columns.GetPreviousVisibleColumn;
          GetNextNode := @FTree.GetPreviousVisible;
        end
        else
        begin
          GetStartColumn := @FTree.Header.Columns.GetFirstVisibleColumn;
          GetNextColumn := @FTree.Header.Columns.GetNextVisibleColumn;
          GetNextNode := @FTree.GetNextVisible;
        end;
 
        // Advance to next/previous visible column/node.
        Node := FNode;
        col := GetNextColumn(FColumn, True);
        repeat
          // Find a column for the current node which can be focused.
          while (col > NoColumn) and
            not TVirtualStringTreeHack(FTree).DoFocusChanging(FNode, node, FColumn, col)
          do
            col := GetNextColumn(col, True);
 
          if col > NoColumn then
          begin
            // Set new node and column in one go.
            TVirtualStringTreeHack(FTree).SetFocusedNodeAndColumn(node, col);
            Break;
          end;
 
          // No next column was accepted for the current node. So advance to next node and try again.
          node := GetNextNode(node);
          col := GetStartColumn();
        until node = nil;
 
        FTree.EndEditNode;
        Key := 0;
        if node <> nil then
        begin
          FTree.FocusedNode := node;
          FTree.FocusedColumn := col;
        end;
        if FTree.CanEdit(FTree.FocusedNode, FTree.FocusedColumn) then
          with TVirtualStringTreeHack(FTree) do
          begin
            EditColumn := FocusedColumn;
            DoEdit;
          end;
      end;
 
    VK_UP,
    VK_DOWN:
      begin
        // Forward the keypress to the tree. It will asynchronously change the focused node.
        PostMessage(FTree.Handle, WM_KEYDOWN, Key, 0);
        Key := 0;
      end;
  end;
end;
 
//------------------------------------------------------------------------------
 
function TVTStringEditLink.BeginEdit: Boolean; stdcall;
begin
  Result := True;
  FEdit.Show;
  FEdit.SetFocus;
end;
 
//------------------------------------------------------------------------------
 
function TVTStringEditLink.CancelEdit: Boolean; stdcall;
begin
  Result := True;
  FEdit.Hide;
end;
 
//------------------------------------------------------------------------------
 
function TVTStringEditLink.EndEdit: Boolean; stdcall;
var
  Buffer: array[0..1024] of Char;
  S: String;
begin
  Result := True;
 
  S := FEdit.Text;
  if FEdit.Modified then
    FTree.Text[FNode, FColumn] := FEdit.Text;
  FEdit.Hide;
  FTree.SetFocus;
end;
 
//------------------------------------------------------------------------------
 
function TVTStringEditLink.GetBounds: TRect; stdcall;
begin
  Result := FEdit.BoundsRect;
end;
 
//------------------------------------------------------------------------------
 
function TVTStringEditLink.PrepareEdit(ATree: TBaseVirtualTree; ANode: PVirtualNode;
  AColumn: TColumnIndex): Boolean; stdcall;
begin
  Result := True;
  FTree := ATree as TVirtualStringTree;
  FNode := ANode;
  FColumn := AColumn;
 
  FEdit.Free;
  FEdit := TEdit.Create(nil);
  FEdit.Visible := False;
  FEdit.Parent := ATree;
  FEdit.Font.Color := clWindowText;
  FEdit.HandleNeeded;
  FEdit.Text := FTree.Text[FNode, FColumn];;
  FEdit.OnKeyDown := @EditKeyDown;
  FEdit.OnExit := @EditExit;
end;
 
//------------------------------------------------------------------------------
 
procedure TVTStringEditLink.ProcessMessage(var Message: TMessage); stdcall;
begin
  FEdit.WindowProc(Message);
end;
 
//------------------------------------------------------------------------------
 
procedure TVTStringEditLink.SetBounds(R: TRect); stdcall;
var
  Dummy: Integer;
begin
  FTree.Header.Columns.GetColumnBounds(FColumn, Dummy, R.Right);
  FEdit.BoundsRect := R;
end;
 
end.
 

UGerd
Lazarusforum e. V.
Beiträge: 18
Registriert: Fr 4. Mär 2011, 17:00
OS, Lazarus, FPC: Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hamburg

Re: virtualTreeView als Grid

Beitrag von UGerd »

@wp_xyz:
Manchmal werden umgeäußerte Wünsche war. Nicht nur, dass mein Grid sich nun so Verhält, wie erwartet. Die Verwendung eigener Editor - Komponenten war für die Zukunft geplant. Mit wenigen Anpassungen deines Quelltextes sollten sich auch andere Editor - Komponenten verwenden lassen.
Du hast einem Anfänger tagelange Arbeit erspart.
Danke!
PS.
Ich habe parallel den Quelltext der Unit VirtualTrees durchforstet, um den Ursprung dieses unerwartetem Verhaltens zu finden, leider ohne Erfolg.

UGerd
Lazarusforum e. V.
Beiträge: 18
Registriert: Fr 4. Mär 2011, 17:00
OS, Lazarus, FPC: Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hamburg

Re: virtualTreeView als Grid

Beitrag von UGerd »

@wp_xyz:
falls es dich weiterhin interessiert:
Im oben erwähntem Tutorial wird empfohlen, bei OnFocusChanged VST.Refresh auszulösen. Dies verträgt sich nicht mit deiner Editor Implementation. Nach dem Wechsel aus dem editierten Feld wird ein Exception der Klasse external ausgelöst
Ich lasse es einfach weg.
Allerdings sehe ich immer noch eine Unschönheit: Es bleibt nach dem editieren und wandern via Tab immer noch ein Feld über dem aktuell fokussiertem grau!

wp_xyz
Beiträge: 5050
Registriert: Fr 8. Apr 2011, 09:01

Re: virtualTreeView als Grid

Beitrag von wp_xyz »

Das Demo-Projekt "Advanced/GridDemo" spielt mit Refresh im OnFocusChanged völlig verrückt, auch ohne meinen Editor. Refresh musste ich in diesem Event noch nie aufrufen. Dieser Satz steht schon seit der allerersten Version in dem Tutorial (2008), vielleicht gab es damals noch Probleme mit der Lazarus-Adaption?

Siehst du das mit dem grauen Feld auch in dem GridDemo aus dem Advanced-Projekt? Das läuft bei mir einwandfrei. Falls das auch bei dir so ist, müsstest du dir die Mühe machen, ein kleines Projekt zu erstellen, das den Fehler zeigt und das du hier hochladen kannst. Irgendwas machst du falsch, aber meine hellseherischen Fähigkeiten sind beschränkt...

UGerd
Lazarusforum e. V.
Beiträge: 18
Registriert: Fr 4. Mär 2011, 17:00
OS, Lazarus, FPC: Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hamburg

Re: virtualTreeView als Grid

Beitrag von UGerd »

Hallo,
Ich habe mir "Advanced/GridDemo" angesehen. Hier sehe ich graue Felder, und sehe keinen Grund hierfür. Ob es einen Zusammenhang mit meinem Problem gibt?
Andere User haben ähnliche Probleme, wenn auch nicht gleiche: http://www.soft-gems.net/forum/viewtopic.php?f=6&t=2581

Ich habe ein Demo Projekt und einen Screenshot von "Advanced/GridDemo" erstellt, kann sie aber nicht als Zip hochladen.
Also hänge ich den Quelltext an und hoffe, das diese Methode nicht zu unbequem wird. Nebenbei: Nach dem hier Einfügen ist meine Formatierung zerschossen :?:
Nach dem Kompilieren kannst du mit "Btn" Nodes und Grid erzeugen. In ein Feld klicken, F2 zum Ändern, und mit mehrmaligem Tab bis in die nächste Zeile wandern. Nun sollte ein Feld in der ursprünglichen Zeile "Grayed" sein.

-------------------------------------------------------------------------------------------------------------------------------------------------------------

Code: Alles auswählen

 
 
unit fmain;
 
{$mode objfpc}{$H+}
 
interface
 
uses
      Classes, SysUtils, FileUtil, VirtualTrees, Forms, Controls, Graphics,
			Dialogs, StdCtrls, LCLType, ExtCtrls, VTEditor;
 
type
 
      PGridData = ^TGridData;
      TGridData = Record
        Column1: String[255];
        Column2: String[255];
        Column3: String[255];
     end;
 
      { TForm1 }
      TForm1 = class(TForm)
	Btn: TButton;
	Panel1: TPanel;
	VST: TVirtualStringTree;
	procedure BtnClick(Sender: TObject);
	procedure VSTChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
	procedure VSTCreateEditor(Sender: TBaseVirtualTree;
					Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
	procedure VSTFocusChanged(Sender: TBaseVirtualTree;
						Node: PVirtualNode; Column: TColumnIndex);
	procedure VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
	procedure VSTGetNodeDataSize(Sender: TBaseVirtualTree;
						var NodeDataSize: Integer);
	procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
					Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
	procedure VSTKeyDown(Sender: TObject; var Key: Word;
									Shift: TShiftState);
	procedure VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
							Column: TColumnIndex; const NewText: String);
      private
            { private declarations }
      public
            { public declarations }
      end;
 
var
      Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.BtnClick(Sender: TObject);
var
  Node: PVirtualNode;
  Data: PGridData;
  Col: TVirtualTreeColumn;
  i: Integer;
begin
 
  VST.WantTabs:= true;
 
  for i:= 0 to 10 do
  begin
    Node:= VST.AddChild(nil);
    Data:= VST.GetNodeData(Node);
 
    with Data^ do
    begin
      Column1:= 'Ändern 1';
      Column2:= 'Ändern 2';
      Column3:= 'Ändern 3';
    end;
  end;
 
  with VST.TreeOptions do
  begin
    MiscOptions:= MiscOptions + [toGridExtensions, toEditable];
    SelectionOptions:= SelectionOptions + [toExtendedFocus];
  end;
 
  with VST.Header do
    Options:= Options + [hoVisible];
 
  with VST.Header.Columns do
  begin
    clear;
    Col:= Add;
    Col.Options:= Col.Options - [coAllowFocus, coEditable];
    Col.Text:= 'MainColumn';
    Col.Width:= 100;
 
    For i:= 1 to 3 do
    begin
      Col:= Add;
      Col.Options:= Col.Options + [coAllowFocus, coEditable];
      Col.Text:= 'Column' + IntToStr(i);
      Col.Width:= 100;
    end;
  end;
end;
 
procedure TForm1.VSTChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
 
end;
 
procedure TForm1.VSTCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode;
			Column: TColumnIndex; out EditLink: IVTEditLink);
begin
  EditLink := TVTStringEditLink.Create;
end;
 
procedure TForm1.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
			Column: TColumnIndex);
begin
      //Sender.Refresh;  //Verursacht Exeption
end;
 
procedure TForm1.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  Data: PGridData;
begin
  Data:= VST.GetNodeData(Node);
 
  if Assigned(Data) then
  with Data^ do
  begin
    Column1:= '';
    Column2:= '';
    Column3:= '';
  end;
end;
 
procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree;
			var NodeDataSize: Integer);
begin
  NodeDataSize:= SizeOf(TGridData);
end;
 
procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
			Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
var
  Data: PGridData;
begin
  Data:= VST.GetNodeData(Node);
 
  if Assigned(Data) then
  with Data^ do
  Case Column of
    1: CellText:= Column1;
    2: CellText:= Column2;
    3: CellText:= Column3;
  end;
end;
 
procedure TForm1.VSTKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
 
end;
 
procedure TForm1.VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
			Column: TColumnIndex; const NewText: String);
var
  Data: PGridData;
begin
  Data := Sender.GetNodeData(Node);
 
  if Assigned(Data) then
  with Data^ do
  Case Column of
    1:  Column1:= NewText;
    2:  Column2:= NewText;
    3:  Column3:= NewText;
  end;
end;
 
end.
 

wp_xyz
Beiträge: 5050
Registriert: Fr 8. Apr 2011, 09:01

Re: virtualTreeView als Grid

Beitrag von wp_xyz »

Du müsstest noch das Formular hochladen. Ich kann das zwar aufgrund der pas-Datei grob rekonstruieren, aber ich weiß nicht, welche Properties du am VST eingestellt hast. Wenn das mit dem zip wieder nicht klappt, das Formular rechts anklicken - "View source (.lfm)" - den ganzen erscheinenden Text markieren und ins Posting kopieren.

Die grauen und gelben Felder in dem Demo sind bewusst durch einen OnBeforeCellPaint-Eventhandler erzeugt.

[EDIT] Ich sehe gerade, du setzst ja die Options zur Laufzeit, dann brauche ich das Formular nicht.

wp_xyz
Beiträge: 5050
Registriert: Fr 8. Apr 2011, 09:01

Re: virtualTreeView als Grid

Beitrag von wp_xyz »

Ja, setzt sehe ich diese Felder auch. Diese grauen Felder tragen das Attribut "Selected". VTV unterscheidet zwischen "Focused" und "Selected", mein Code hat nur das "Focused" behandelt, zusätzlich muss man noch "VT.Selected[node] := true" setzen.

Ich kopiere hier ein Update der Keydown-Methode des Editors, in der dieser Fehler behoben ist und die etwas vereinfacht ist:

Code: Alles auswählen

 
procedure TVTStringEditLink.EditKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
var
  node: PVirtualNode;
  col: TColumnIndex;
  GetStartColumn: function(ConsiderAllowFocus: Boolean = False): TColumnIndex of object;
  GetNextColumn: function(Column: TColumnIndex; ConsiderAllowFocus: Boolean = False): TColumnIndex of object;
  GetNextNode: TGetNextNodeProc;
begin
  case Key of
    VK_ESCAPE:
      begin
        FTree.CancelEditNode;
        Key := 0;
      end;
    VK_RETURN:
      begin
        FTree.EndEditNode;
        Key := 0;
        if (ssShift in Shift) then
          node := FTree.GetPreviousVisible(FNode, True)
        else
          node := FTree.GetNextVisible(FNode, True);
        if node <> nil then
        begin
          FTree.Selected[node] := true;
          FTree.EditNode(node, FTree.FocusedColumn);
        end;
      end;
    VK_TAB:
      begin
        FTree.EndEditNode;
        Key := 0;
        if ssShift in Shift then
        begin
          GetStartColumn := @FTree.Header.Columns.GetLastVisibleColumn;
          GetNextColumn := @FTree.Header.Columns.GetPreviousVisibleColumn;
          GetNextNode := @FTree.GetPreviousVisible;
        end
        else
        begin
          GetStartColumn := @FTree.Header.Columns.GetFirstVisibleColumn;
          GetNextColumn := @FTree.Header.Columns.GetNextVisibleColumn;
          GetNextNode := @FTree.GetNextVisible;
        end;
 
        // Advance to next/previous visible column/node.
        Node := FNode;
        col := GetNextColumn(FColumn, True);
        repeat
          // Find a column for the current node which can be focused.
          while (col > NoColumn) and
            not TVirtualStringTreeHack(FTree).DoFocusChanging(FNode, node, FColumn, col)
          do
            col := GetNextColumn(col, True);
 
          if col > NoColumn then
          begin
            FTree.FocusedNode := node;
            FTree.Selected[node] := true;
            FTree.FocusedColumn := col;
            FTree.EditNode(node, col);
            Break;
          end;
 
          // No next column was accepted for the current node.
          // So advance to next node and try again.
          node := GetNextNode(node);
          col := GetStartColumn();
        until node = nil;
      end;
 
    VK_UP,
    VK_DOWN:
      begin
        // Forward the keypress to the tree.
        // It will asynchronously change the focused node.
        PostMessage(FTree.Handle, WM_KEYDOWN, Key, 0);
        Key := 0;
      end;
  end;
end;
 

UGerd
Lazarusforum e. V.
Beiträge: 18
Registriert: Fr 4. Mär 2011, 17:00
OS, Lazarus, FPC: Lazarus 2.2.4 (rev lazarus_2_2_4) FPC 3.2.2 x86_64-win64-win32/win64
CPU-Target: 64Bit
Wohnort: Hamburg

Re: virtualTreeView als Grid

Beitrag von UGerd »

Vielen Dank,
für den excellenten Support! Das kann keine kommerzielle Software bieten!
Jetzt kann ich mit meinem Projekt weitermachen. :D
Gruß
UGerd

Antworten