Welche uses braucht GetSubDirectories?

Rund um die LCL und andere Komponenten
ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

Lion hat geschrieben:ich habe rausgefunden, dass es an dieser Zeile liegt ->

Code: Alles auswählen

if Node.Expanded or (not Node.HasChildren) then Exit;
auskommentiert wird auch dem Root ein Folder-Icon verpasst.
Seltsam. Und inkonsistent. Aber mag sein, ich habe mich wie gesagt noch nie mit solchen (wie ich finde nutzlosen) Icons anfreunden können. Wenn Ihr es nicht erwähnt hättet, wäre mir im Leben nie aufgefallen, daß die bei mir nicht vorhanden sind... :|

Aber wo wir schon mal dabei sind, die vor Unkenntnis triefende Frage: Wo habt Ihr diese Icons eigentlich her? Ich hatte erwartet, im Objektinspektor unter "Images" eine Grafikdatei laden zu können, dem ist aber nicht so. Wie muß man es also anstellen, um diese Icons reinzubasteln? Irgendeine Ressourcendatei ins Verzeichnis und anbinden?
Lion hat geschrieben:... bevor ich ShellTreeView1.Root := ''; nicht setze wird bei mir die View nicht aktualisiert.
Was meinst Du mit "View nicht aktualisiert"? Überhaupt nicht, oder nur bezogen auf diese Icons? Wenn ersteres, kann das eigentlich nur ein Bug sein - bei mir funktioniert das völlig problemlos. Es wäre auch absolut verwunderlich, denn die Standardzeile bei TShellTreeView.SetRoot müßte doch lauten "if ARoot <> FRoot then begin FRoot := ARoot; UndjetztLeseDasVerzeichnisEinUndMale; end;" ... Irgendwie ergibt das keinen Sinn. Bei mir ist '' schlicht das Basisverzeichnis meines Dateisystems. Und einfach mal Ladezeiten zu verdoppeln, kann man wohl unmöglich als "Lösung" bezeichnen... Wenn's wieder nur die Folder-Icons betrifft, okay, dann werden die beim Zeichnen des Ganzen wohl an einer suboptimalen Stelle eingehängt worden sein, das kann schon sein.

Das Problem, wenn Du die Zeile wegläßt, wird halt sein, daß bei großen, vielfach expandierten Verzeichnisbäumen die Malaktion irgendwann merklich Zeit verschlingt. Wie gesagt, das ist erstmal nur ein Workaround, eigentlich müßte diese Prüfung auf HasChildren genau einmal pro Node, und zwar bei dessen Erstellung stattfinden, nicht bei jedem Redraw.

Gruß Rüdiger

Lion
Beiträge: 207
Registriert: Mo 24. Mär 2014, 09:58

Re: Welche uses braucht GetSubDirectories?

Beitrag von Lion »

Die Icons lade ich in die ImageList, der TreeView wird diese angebunden und wie folgt die Icons jedem Item zugewiesen: Node.ImageIndex := 1; :mrgreen:

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

Lion hat geschrieben:Die Icons lade ich in die ImageList, der TreeView wird diese angebunden und wie folgt die Icons jedem Item zugewiesen: Node.ImageIndex := 1; :mrgreen:
Sorry, stehe gerade auf dem Schlauch... Welche ImageList? Meinst Du TShellTreeView.Images? Da kann ich - im Objektinspektor jedenfalls - nichts "laden".

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2909
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Welche uses braucht GetSubDirectories?

Beitrag von m.fuchs »

Du musst eine TImageList auf dein Formular legen und kannst diese dann unter TShellTreeView.Images auswählen. Diese ImageList kannst du dann mit den entsprechenden Bildern befüllen.
0118999881999119725-3

Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

Okay, alles klar, danke, Michael!

Jaja - ich gehöre halt noch zu der aussterbenden Sorte Menschen, denen es verwehrt ist, die Welt als Ansammlung von Icons zu begreifen... :oops:

Gruß Rüdiger

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2909
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Welche uses braucht GetSubDirectories?

Beitrag von m.fuchs »

Verständlich, schließlich sind GUI ein Rückschritt in der Entwicklung.
Nur Kleinkinder zeigen mit dem Mauszeiger Finger auf etwas und klicken sagen "Gaaah", bevor sie später das mächtige Tool "Sprache" erlernen. :wink:
0118999881999119725-3

Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

m.fuchs hat geschrieben:... schließlich sind GUI ein Rückschritt in der Entwicklung.
Nein, das nicht. Ich neige da nur zur Sparsamkeit und empfinde die Bilderflut eher als Lärm bzw. eine Art Umweltverschmutzung.
m.fuchs hat geschrieben:... das mächtige Tool "Sprache"... :wink:
Da magst Du blinzeln, aber dieses in der Tat "mächtige Tool" ist tatsächlich zunehmend beklagenswert ramponiert, wie wir nicht erst seit PISA wissen.

Okay...: Das ewige Klagelied der Alten... :cry:

Gruß Rüdiger

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2909
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Welche uses braucht GetSubDirectories?

Beitrag von m.fuchs »

ruewa hat geschrieben:
m.fuchs hat geschrieben:... das mächtige Tool "Sprache"... :wink:
Da magst Du blinzeln, aber dieses in der Tat "mächtige Tool" ist tatsächlich zunehmend beklagenswert ramponiert, wie wir nicht erst seit PISA wissen.
Ich bin da ganz deiner Meinung.
0118999881999119725-3

Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

Dazu paßt ja wie die Faust aufs Auge:
Die ursprüngliche Raspberry Pi Modell B Computer ging auf Verkauf in februar 2012 und einen neuen Standard das Bruchrisiko der dominanz des PC in zu Hause und Ausbildung Märkte. (...) Die Platinen bietet eine Plattform für Kinder und erwachsene von einem beliebigen Hintergrund Übernahme informatik Kenntnisse und entwickeln die Zukunft world-wide -Web und das Internet der Dinge. Während die Raspberry Pi Boards wurden in erster Linie für Ausbildung, sie sehr beliebt geworden mit Herstellern von eingebetteter Systeme.
Und da jammern die Pädagogen, der heutigen Jugend sei die Fähigkeit abhanden gekommen, den Inhalt geschriebener Texte zu erfassen. Viel schlimmer: Jetzt trifft's auch noch uns Alte mit Macht, ist das bitter...

Wobei, es könnte eine Zeit anbrechen, wo das echt von Vorteil ist. Immerhin enthält die Seite 18 bunte Bilder und 14 Icons, wenn ich recht gezählt habe.

haubdsach iss, das di rubbel rolt!!!!!!!!!!!!!

Oder so...

Gruß Rüdiger

Sorry für's OT...

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2909
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Welche uses braucht GetSubDirectories?

Beitrag von m.fuchs »

ruewa hat geschrieben:
Die ursprüngliche Raspberry Pi Modell B Computer ging auf Verkauf in februar 2012 und einen neuen Standard das Bruchrisiko der dominanz des PC in zu Hause und Ausbildung Märkte. (...) Die Platinen bietet eine Plattform für Kinder und erwachsene von einem beliebigen Hintergrund Übernahme informatik Kenntnisse und entwickeln die Zukunft world-wide -Web und das Internet der Dinge. Während die Raspberry Pi Boards wurden in erster Linie für Ausbildung, sie sehr beliebt geworden mit Herstellern von eingebetteter Systeme.
Klingt nach Google Translator.
0118999881999119725-3

Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

m.fuchs hat geschrieben:Klingt nach Google Translator.
Na klar! Die verdienstvollste Erfindung seit der Entdeckung der Cola-Mentos-Fontäne, mit dem Zeug zur Begründung eines neues Schulfachs (die anderen kann man sich dafür dann sparen)... Womit sich auch mal wieder die zivilisatorische Vorreiterrolle des Versandhandels bestätigt hätte...

Oder frei nach Armstrong: "That's one small click for [a] man, one giant mud leap for mankind."

Aber stimmt schon: Ohne Icons wird das eng...

Gruß Rüdiger

Lion
Beiträge: 207
Registriert: Mo 24. Mär 2014, 09:58

Re: Welche uses braucht GetSubDirectories?

Beitrag von Lion »

ruewa hat geschrieben:
Dein Screenshot hat doch ein Icon auf der Ebene "C:\" ? Willst Du das weghaben? Dann setz ShellTreeView1.ShowRoot auf false, wenn Dir das besser gefällt. Ansonsten würde ich sagen, jetzt laß es mal gut sein... :?
Komisch, ShowRoot:=False; funktioniert bei mir nicht. Ist das ein Bug? Wie sieht es bei euch aus?

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

Okay, back to Topic. Es gibt eine schlechte Nachricht und eine gute:

Die Schlechte ist: Der vor einigen Tagen entwickelte Workaround mit der in TShellTreeView.OnCustomDrawItem eingehängten Prüfung auf Unterverzeichnisse arbeitet nur dann (und selbst dann nur einigermaßen) fehlerfrei, wenn die Property TShellTreeView.ObjectTypes auf otFolders, nicht aber auf otNonFolders und/oder otHidden gesetzt ist.

Die gute Nachricht: Es gibt dafür eine Lösung, die auch den OnCustomDrawItem-Workaround überflüssig macht.

TShellTreeView enthält zwei zentrale Methoden für den Aufbau des Verzeichnisbaums: Die übergeordnete ist PopulateTreeNodeWithFiles. Sie wiederum ruft GetFilesInDir auf, wo der eigentliche Einlesevorgang stattfindet und entschieden wird, ob eine Datei bzw. ein Verzeichnis angezeigt wird oder nicht (abhängig von den ObjectTypes-Einstellungen).

Die Property ObjectTypes legt fest, ob die ShellTreeView nur Verzeichnisse oder (auch oder ausschließlich) Dateien anzeigen soll, und ob versteckte Verzeichnisse bzw. Dateien ebenfalls angezeigt werden sollen. Im Normalfall wird die ShellTreeView zusammen mit einer (ankoppelbaren) ShellListView verwendet, dann macht es kaum Sinn, sie etwas anderes als ausschließlich Verzeichnisse anzeigen zu lassen. Selbst die Folder-Anzeige ganz wegzuschalten, ist möglich, auch wenn das Ergebnis dann ziemlich unsinnig wird. Aber was soll's: Es gibt nun einmal diese Einstellungsmöglichkeiten, also sollten sie auch korrekt funktionieren. Doch genau da gibt es ein tieferliegendes Problem, weil TShellTreeView hier noch einen weiteren Fehler im Gebälk hat.

Zunächst: Welche Bedeutung haben die Einstellungen von ObjectTypes eigentlich? Auf den zweiten Blick taucht da nämlich eine Schwierigkeit auf: otFolders und otNonFolders ist klar: Einmal sind Verzeichnisse gemeint, das andere steht für Dateien. Aber was meint otHidden? Schließlich gibt es sowohl versteckte Directories als auch versteckte Files. Hier braucht es also eine Festlegung. Die lautet: otHidden ist den beiden anderen Einstellungen untergeordnet und wird je nach deren Stellung interpretiert: Wenn otFolders gesetzt ist, sorgt otHidden dafür, daß auch versteckte Verzeichnisse angezeigt werden - und entsprechend muß otNonFolders gesetzt sein, um zusammen mit otHidden auch versteckte Dateien sichtbar zu machen. Einen Sonderfall stellen die Verzeichnisse "." und ".." dar, die werden unter keinen Umständen angezeigt.

Ich habe mich dafür entschieden, eine zusätzlich Funktion namens TCustomShellTreeView.NodeHasUnbornChild zu implementieren, die aus PopulateTreeNodeWithFiles heraus abgefragt wird. Die hat den Vorteil, daß sie nicht (wie GetFilesInDir) das gesamte Unterverzeichnis einlesen muß, sondern abbricht, sobald ein Treffer gefunden wurde - der Nachteil ist, daß sie GetFilesInDir in Teilen verdoppelt.

Das alleine funktioniert aber immer noch nicht befriedigend. Das Problem dabei ist, daß TShellTreeView bereits in ihrem Konstruktor Create angewiesen wird, das Base-Verzeichnis einzulesen. Zu diesem Zeitpunkt sind aber weder Root noch ObjectTypes oder sonst irgendwelche Properties aus den Ressourcen geladen. Damit das nicht schiefgeht, wird in Create erst einmal ObjectTypes auf otFolders gesetzt, egal, was die Komponente eigentlich später mal anzeigen soll. Nun wird PopulateTreeNodeWithFiles mit dieser Einstellung gleich zweimal durchlaufen, erst dann werden die Properties aus den Ressourcen eingelesen. Und zwar zunächst FileSortType, dann Root und erst ganz zum Schluß ObjectTypes. Jede dieser Property-Zuweisungen triggert PopulateTreeNodeWithFiles (insgesamt 5-mal), nur dummerweise ObjectTypes nicht, deren write-Pfad direkt zum Feld FObjectTypes führt. Letztlich führt das dazu, daß die erste Anzeige der ShelltreeView die Einstellungen von ObjectTypes schlicht ignoriert. Das wiederum ist nicht nur lästig, sondern kann auch zu echten Fehlern führen, weil nämlich u.U. ein Verzeichnis erst gar nicht geöffnet werden kann, das eigentlich sehr wohl ChildNodes enthält. Aus diesem Grund habe ich auch noch eine zusätzliche Prozedur SetObjectTypes hinzugefügt und die Zuweisung der Property ObjectTypes darauf umgebogen. Dort wird PopulateTreeNodeWithFiles ein sechstes Mal getriggert, bevor erstmals was auf dem Bildschirm zu sehen ist - was gewiß keine schöne Lösung ist, aber so funktioniert das Ganze nun immerhin (jedenfalls soweit ich sehen kann).

Hier nun die Modifikationen der Unit ShellCtrls.pas:

Code: Alles auswählen

{*************** Modifikationen der TCustomShellTreeView-Deklaration: ***************}
 
  TCustomShellTreeView = class(TCustomTreeView)
  private
    ...
{+} procedure SetObjectTypes(AValue : TObjectTypes);
  protected
    { Other methods specific to Lazarus }
{+} function NodeHasUnbornChild(ANode : TTreeNode) : Boolean;
    ...
  public
    { Properties }
{-  property ObjectTypes: TObjectTypes read FObjectTypes write FObjectTypes;  }
{+} property ObjectTypes: TObjectTypes read FObjectTypes write SetObjectTypes;
    ...
end;
 
{*************** Zusätzliche Prozedur TCustomShellTreeView.SetObjectTypes: ***************}
 
procedure TCustomShellTreeView.SetObjectTypes(AValue : TObjectTypes);
begin
  if FObjectTypes = AValue then Exit;
  FObjectTypes := AValue;
  Refresh(nil);     // Refresh with Root
end;
 
{*************** Zusätzliche Funktion TCustomShellTreeView.NodeHasUnbornChild: ***************}
 
function TCustomShellTreeView.NodeHasUnbornChild(ANode: TTreeNode): Boolean;
var
  DirInfo: TSearchRec;
  FindResult: Integer;
  IsDirectory,
  IsValidDirectory,
  IsHidden,
  HasChildDir,
  HasChildFile,
  HasHiddenChildDir,
  HasHiddenChildFile : Boolean;
begin
  Result := false;
  FindResult := FindFirstUTF8(IncludeTrailingPathDelimiter(GetPathFromNode(ANode)) + AllFilesMask,
                                faAnyFile and faDirectory, DirInfo);
  while (FindResult = 0) and (not Result) do
  begin
    IsDirectory := (DirInfo.Attr and FaDirectory = FaDirectory);
    IsValidDirectory := IsDirectory and (DirInfo.Name <> '.') and (DirInfo.Name <> '..');
    IsHidden := (DirInfo.Attr and faHidden = faHidden);
    {$IFDEF Unix}
    if (DirInfo.Name<>'') and (DirInfo.Name[1]='.') then IsHidden := true;
    {$ENDIF}
    HasChildDir := IsValidDirectory and (not IsHidden) and (otFolders in FObjectTypes);
    HasChildFile := (not IsDirectory) and (not IsHidden) and (otNonFolders in FObjectTypes);
    HasHiddenChildDir := IsValidDirectory and IsHidden and
                         (otFolders in FObjectTypes) and (otHidden in FObjectTypes);
    HasHiddenChildFile := (not IsDirectory) and IsHidden and
                         (otNonFolders in FObjectTypes) and (otHidden in FObjectTypes);
    if HasChildDir or HasChildFile or HasHiddenChildDir or HasHiddenChildFile then Result := true
    else FindResult := FindNextUTF8(DirInfo);
  end;
  FindCloseUTF8(DirInfo);
end;
 
{*************** Modifikationen der Funktion TCustomShellTreeView.PopulateTreeNodeWithFiles: ***************}
 
function TCustomShellTreeView.PopulateTreeNodeWithFiles(ANode: TTreeNode; ANodePath: string): Boolean;
var
  ....
begin
  ...
    for i := 0 to Files.Count - 1 do
    begin
      NewNode := Items.AddChildObject(ANode, Files.Strings[i], nil); //@Files.Strings[i]);
{-    NewNode.HasChildren := Files.Objects[i] <> nil; // This marks if the node is a directory }
{+}   NewNode.HasChildren := (Files.Objects[i] <> nil) and NodeHasUnbornChild(NewNode);
    end;
  ...
end;
Ich bin noch etwas unentschlossen, ob ich daraus einen Patch machen und ihn in den Bug-Tracker geben soll. Denn eigentlich hätte die Komponente eine grundlegendere Revision verdient. Wie seht Ihr das?

Auch müßte ich erstmal die aktuelle Entwicklerversion installieren, mein Stand ist Lazarus 1.2.4. Vor allem aber habe ich keine Möglichkeit, diese Modifikation unter Windows zu testen. Ich würde das weitere Vorgehen daher auch von Eurer Reaktion abhängig machen, insbesondere von einer Rückmeldung, ob das Ganze auch unter Windows fehlerfrei funktioniert. Deshalb hier noch das Testprogramm (das auch die modifizierte ShellCtrls.pas enthält):
Test_ShellTreeView.zip
Korrigierte Version
(134.69 KiB) 112-mal heruntergeladen
Gruß Rüdiger
Zuletzt geändert von ruewa am Mo 9. Feb 2015, 16:52, insgesamt 1-mal geändert.

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

Re: Welche uses braucht GetSubDirectories?

Beitrag von theo »

Seit Revision 47650 werden Expand Signs nur noch wenn nötig gezeichnet.
http://svn.freepascal.org/cgi-bin/viewv ... ortby=date

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Welche uses braucht GetSubDirectories?

Beitrag von ruewa »

theo hat geschrieben:Seit Revision 47650 werden Expand Signs nur noch wenn nötig gezeichnet.
http://svn.freepascal.org/cgi-bin/viewv ... ortby=date
Danke für den Hinweis! Ich sollte mir wohl doch mal die Trunc-Version ans Bein binden...

Aaaber: Das ist nur eine halbherzige Lösung, meine geht deutlich darüber hinaus. Und zwar beherzigt diese Änderung nur den Sonderfall, daß ObjectTypes = [otFolders] ist, und nur das. Sicher: Das deckt in der Praxis wahrscheinlich 97 % aller Anwendungsfälle ab, ist aber nach wie vor nicht konsistent mit den Einstellungsmöglichkeiten von ObjectType.

Das ist weniger theoretisch, als es klingt. Denn sobald man mit der ShellTreeView auch versteckte Verzeichnisse sichtbar machen möchte, ist die Erstanzeige schlicht fehlerhaft und alle weiteren Anzeigen pflastern dann die Landschaft weiterhin unterschiedslos mit diesen Expand Signs, auch in der neuen Revision.

Insofern ist meine Lösung damit keineswegs gegenstandslos geworden.

Gruß Rüdiger

Antworten