AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi VirtualTreeView, OnGetImageIndexEx und OverlayImages
Thema durchsuchen
Ansicht
Themen-Optionen

VirtualTreeView, OnGetImageIndexEx und OverlayImages

Ein Thema von Codehunter · begonnen am 20. Mär 2018 · letzter Beitrag vom 21. Mär 2018
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Codehunter
Codehunter

Registriert seit: 3. Jun 2003
Ort: Thüringen
2.272 Beiträge
 
Delphi 10.4 Sydney
 
#1

VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 15:12
Hallo!

Ich ärgere mich schon eine ganze Weile mit dem VST herum. Ich möchte ein Overlay-Image über das Node-Symbol legen. Die normalen Images und die Overlays liegen in verschiedenen ImageLists, daher verwende ich OnGetImageIndexEx:
Delphi-Quellcode:
procedure TForm1.tvGridGetImageIndexEx(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
  var Ghosted: Boolean; var ImageIndex: TImageIndex;
  var ImageList: TCustomImageList);
var
  D: PDbTreeNodeData;
begin
  ImageIndex:= -1;
  if Column = 0 then begin
    case Kind of
      ikNormal, ikSelected:
      begin
        ImageList:= ilIcons;
        D:= Sender.GetNodeData(Node);
        if D <> NIL then begin
          ImageIndex:= D^.Data.ImageIndex;
        end;
      end;

      ikOverlay:
      begin
        ImageList:= ilOverlays;
        D:= Sender.GetNodeData(Node);
        if D <> NIL then begin
          ImageIndex:= D^.Data.OverlayIndex;
        end;
      end;
    end;
  end;
end;
Jedoch wird kein Overlay gepinselt. Der selbe Code in OnGetImageIndex (ohne -Ex) funktioniert einwandfrei. Nur eben mit dem Unterschied, dass ich hier alle Images in eine gemeinsame Liste packen muss. Das gefällt mir aber nicht so gut.

Laut Debugger passt alles, sämtliche Zuweisungen, ImageIndizes und Imagelisten sind so wie sie sein sollen. Allerdings blicke ich im VST-Quellcode nicht wirklich durch, der ist ziemlich verworren. Darum kann ich nicht nachvollziehen, ob OnGetImageIndexEx intern anders behandelt wird als OnGetImageIndex (abgesehen von der Zuweisung der ImageList im Eventhandler)

Grüße
Cody
Ich mache grundsätzlich keine Screenshots. Schießen auf Bildschirme gibt nämlich hässliche Pixelfehler und schadet der Gesundheit vom Kollegen gegenüber. I und E zu vertauschen hätte den selben negativen Effekt, würde aber eher dem Betriebsklima schaden
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 18:58
Vielleicht kann die dieser Abschnitt aus meinen Code helfen, arbeitet mit ListView, der liest ein Verzeichniss ein und gibt es mit icons und mini-Info aus.
Leider weder optimiert, noch gut anzuschauen, zumindest macht es das was ich vorhatte.

Delphi-Quellcode:
procedure GetFiles(const hLV: HWND; Path, Mask: String);
var
  finddata : TWin32FindData;
  hFile : cardinal;
  Loop : dword;
  lvi : TLVItem;
  buf : array[0..25]of char;
  tile : TLVTileInfo;
  fi : TSHFileInfo;
  LVIMark : TLVInsertMark;
  tmp : String;
  i : integer;
begin
 hFile := FindFirstFile(PChar(IncludeTrailingPathDelimiter(Path) + Mask), finddata);
  if(hFile <> INVALID_HANDLE_VALUE) then begin
   LockWindowUpdate(hDlg);
   LastFolder := IncludeTrailingPathDelimiter(Path);
   Loop := 0;
    repeat
     if(finddata.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = 0) then begin

      ZeroMemory(@fi, sizeof(TSHFileInfo));
      ListView_SetImageList(hLV,
       SHGetFileInfo(PChar(IncludeTrailingPathDelimiter(Path) + finddata.cFilename), 0,
       fi, sizeof(TSHFileInfo), SHGFI_SYSICONINDEX or SHGFI_TYPENAME or SHGFI_SMALLICON), LVSIL_SMALL);

      ZeroMemory(@fi, sizeof(TSHFileInfo));
      ListView_SetImageList(hLV,
       SHGetFileInfo(PChar(IncludeTrailingPathDelimiter(Path) + finddata.cFilename), 0,
       fi, sizeof(TSHFileInfo), SHGFI_SYSICONINDEX or SHGFI_TYPENAME or SHGFI_ICON), LVSIL_NORMAL);

      lvi.mask := LVIF_TEXT or LVIF_IMAGE;
      lvi.iItem := Loop;
      lvi.iSubItem := 0;
      lvi.pszText := finddata.cFileName;
     i := 0;
      lvi.iImage := fi.iIcon;
      ListView_InsertItem(hLV, lvi);

      tmp := IntToStr(finddata.nFileSizeLow)+' byte';
      if (finddata.nFileSizeLow / 1024) > 1 then tmp := FloatToStr((finddata.nFileSizeLow / 1024),-1,2)+' kb';
      if (finddata.nFileSizeLow / 1024 / 1024) > 1 then tmp := FloatToStr((finddata.nFileSizeLow / 1024 / 1024),-1,2)+' mb';
      if (finddata.nFileSizeLow / 1024 / 1024 / 1024) > 1 then tmp := FloatToStr((finddata.nFileSizeLow / 1024 / 1024 / 1024),-1,2)+' gb';
      lvi.mask := LVIF_TEXT;
      lvi.iSubItem := 1;
      lvi.pszText := pChar(tmp);
      ListView_SetItem(hLV, lvi);

      lvi.mask := LVIF_TEXT;
      lvi.iSubItem := 2;
      lvi.pszText := fi.szTypeName;
      ListView_SetItem(hLV, lvi);

// ZeroMemory(@buf, sizeof(buf));
// wvsprintf (buf, '%u byte', pchar(@finddata.nFileSizeLow));
      lvi.mask := LVIF_TEXT;
      lvi.iSubItem := 3;
      lvi.pszText := pChar(IntToStr(finddata.nFileSizeLow)); //buf;
      ListView_SetItem(hLV, lvi);

     if GetOSVersion = osXP then begin
      tile.cbSize := sizeof(TLVTileInfo);
      tile.iItem := Loop;
// tile.cColumns := length(colArray);
      tile.puColumns := @colArray[0];
      ListView_SetTileInfo(hLV, tile);
     end;
    LVIMark.cbSize := sizeof(TLVInsertMark);
    LVIMark.dwFlags := LVIM_AFTER;
    LVIMark.iItem := Loop;
    LVIMark.dwReserved := 0;
    ListView_SetInsertMark(hLV, LVIMark);
    if LowerCase(ExtractFileName(SelectedFile)) = LowerCase(finddata.cFileName) then
    begin
{    if LowerCase(ExtractFileName(SelectedFile)) = LowerCase(finddata.cFileName) then
      ListView_SetItemState(hLV, Loop, 0, LVIS_SELECTED);}

      lvi.stateMask := LVIS_SELECTED;
      lvi.state := LVIS_SELECTED;
      SendMessage(hLV, LVM_SETITEMSTATE, Loop, Longint(@lvi))
    end;
    Inc(Loop);
   end;
  until (not FindNextFile(hFile, finddata));
   FindClose(hFile);
  LockWindowUpdate(0);
 end;
end;
Das war mein Versuch eine ListView ähnlich dem Explorer nachzubasteln, primitiv ich weiss.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von Codehunter
Codehunter

Registriert seit: 3. Jun 2003
Ort: Thüringen
2.272 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 19:06
Danke aber leider ist der VirtualTreeView nicht mit dem Listview verwandt. Die sind nicht mal ähnlich. Der VTV bzw. VST ist sehr komplex. Manchmal spielen da kleine Änderungen an den TreeOptions rein, das Theming, Events die bestimmte Parameter gesetzt haben wollen, tausend Möglichkeiten. Das sich OnGetImageIndex und OnGetImageIndexEx unterschiedlich verhalten, das Problem hatte ich auch noch nicht.
Ich mache grundsätzlich keine Screenshots. Schießen auf Bildschirme gibt nämlich hässliche Pixelfehler und schadet der Gesundheit vom Kollegen gegenüber. I und E zu vertauschen hätte den selben negativen Effekt, würde aber eher dem Betriebsklima schaden
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#4

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 19:32
Wenn es so abläuft, wie in anderen Controls mit den Overlays, dann müssen die Overlays zwingend in derselben ImageList liegen, wie die anderen Icons.

Kannst du mal versuchen, die Overlay-Imagelist so aufzubauen, daß die Overlay-Indices in dieser Liste alle >= 15 sind? In dem Fall kann das API-Handling für Overlays nicht mehr verwendet werden.

Sollte das funktionieren, wäre das dann ein Bug im VTV. Ist es aber wohl in jedem Fall, aber dann wüsste ich wie er zu beheben ist.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 19:35
Für TreeView mit verschiedenen Bildern habe ich so etwas mir mal gebastelt.
Garantiert viel zu alt, stammt glaube ich noch aus Delphi 5/6/7 (?) Zeiten.

Delphi-Quellcode:
Procedure CreateImages;
   var
     SysIL: HImageList;
     SFI: TSHFileInfo;
   begin
     MyTreeView.Images := TImageList.Create(Self);
     SysIL := SHGetFileInfo('', 0, SFI, SizeOf(SFI),
     SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
     if SysIL <> 0 then begin
       Images.Handle := SysIL;
       Images.ShareImages := TRUE;
     end;
end;
Das ist praktisch das gleich wie bei dem ListView Beispiel, hier hatte ich es mit TreeView realisiert, diese Routine sammelte mir die Icons. Tut mir leid das ich nicht weiter helfen kann.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von Codehunter
Codehunter

Registriert seit: 3. Jun 2003
Ort: Thüringen
2.272 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 19:42
Wenn es so abläuft, wie in anderen Controls mit den Overlays, dann müssen die Overlays zwingend in derselben ImageList liegen, wie die anderen Icons.
Das gerade nicht, weshalb mir die Implementierung mit OnGetImageIndexEx sehr gut gefällt. Man ist nicht gezwungen, wild zusammengewürfelte Endlos-Imagelisten zu bauen.

Kannst du mal versuchen, die Overlay-Imagelist so aufzubauen, daß die Overlay-Indices in dieser Liste alle >= 15 sind? In dem Fall kann das API-Handling für Overlays nicht mehr verwendet werden.
Ich war praktisch zeitgleich mit deinem Post auch an genau der Sache dran. Der entsprechende Hinweis findet sich als Kommentar in der Virtualtrees.pas:
Delphi-Quellcode:
      // If the user returned an index >= 15 then we cannot use the built-in overlay image drawing.
      // Instead we do it manually.
Genau das war - rein zufällig - bei mir der Fall. So lange ich es mit OnGetImageIndex implementiert hatte, lagen alle Images gemeinsam in einer Imagelist und die Overlay-Images lagen alle oberhalb von Index 15. Wenn ich nun hier einen Overlay-Index kleiner 15 angebe, dann funktioniert das Overlaying auch in OnGetImageIndex nicht mehr.

Sollte das funktionieren, wäre das dann ein Bug im VTV. Ist es aber wohl in jedem Fall, aber dann wüsste ich wie er zu beheben ist.
Ob es ein Bug ist sei mal dahin gestellt. Das scheint durchaus Absicht zu sein:
Delphi-Quellcode:
      if (ImageInfo[iiOverlay].Index > -1) and (ImageInfo[iiOverlay].Index < 15) then
        ExtraStyle := ILD_TRANSPARENT or ILD_OVERLAYMASK and IndexToOverlayMask(ImageInfo[iiOverlay].Index + 1)
      else
        ExtraStyle := ILD_TRANSPARENT;
Allerdings durchschaue ich noch nicht so ganz, was die zusätzlichen Extrastyles bewirken sollen wenn der ImageIndex < 15 ist. Würde man auf diese Extrawürste verzichten, müsste es nach meiner Logik eigentlich immer funktionieren.
Ich mache grundsätzlich keine Screenshots. Schießen auf Bildschirme gibt nämlich hässliche Pixelfehler und schadet der Gesundheit vom Kollegen gegenüber. I und E zu vertauschen hätte den selben negativen Effekt, würde aber eher dem Betriebsklima schaden

Geändert von Codehunter (20. Mär 2018 um 19:47 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#7

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 19:54
. Das scheint durchaus Absicht zu sein:
Na ja, der Entwickler ist stillschweigend davon ausgegangen, daß die Images eben in einer Liste liegen. Bei einem Index < 15 wird nämlich nur die eine Liste zum Zeichnen beider Icons an die DrawImage-Routine übergeben.

DrawImage(Images, Index, Canvas, XPos, YPos, Style[Images.ImageType] or ExtraStyle, DrawEnabled);

Die Entscheidung, ob das Overlay selbst gezeichnet werden muss, ist eben nicht nur vom ImageIndex < 15 abhängig, sondern auch davon, ob beide Imagelists gleich sind. Nur wenn beides zutrifft, kann die vereinfachte Draw-Methode verwendet werden.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Codehunter
Codehunter

Registriert seit: 3. Jun 2003
Ort: Thüringen
2.272 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 20. Mär 2018, 20:04
Wenn man das so betrachtet, dann ist es wohl doch ein Bug "durch Unterlassen" im VST. Ich sehe zumindest keine Prüfung darauf hin, ob die Bilder in der selben oder unterschiedlichen ImageLists liegen. Sollte ich raten dann würde ich vermuten, OnGetImageIndexEx wurde nachträglich "drangeflanscht" und dieser Index-15-Fallstrick dabei vergessen.

Ist das eigentlich der selbe Fallstrick, weshalb TortoiseGit unter Windows 10 Probleme hat, die Overlay-Images in den Explorer einzubauen wenn gleichzeitig die Onedrive-Extension aktiv ist? Da gibts ganz ähnliche Probleme...

Ich hab mal ein bisschen quergelesen und scheinbar ist dieses Index-15-Problem ein Relikt aus 16-Bit-Windows-Zeiten. Ist sowas möglich nach so langer Zeit? Au weia.

@Uwe: Du hast mir jetzt in den letzten Tagen bei mehreren dicken Zeitklauern geholfen
Ich mache grundsätzlich keine Screenshots. Schießen auf Bildschirme gibt nämlich hässliche Pixelfehler und schadet der Gesundheit vom Kollegen gegenüber. I und E zu vertauschen hätte den selben negativen Effekt, würde aber eher dem Betriebsklima schaden
  Mit Zitat antworten Zitat
Benutzerbild von Codehunter
Codehunter

Registriert seit: 3. Jun 2003
Ort: Thüringen
2.272 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 21. Mär 2018, 08:52
Ich habe jetzt die Quick&Dirty-Lösung ausprobiert und in der separaten Operlay-ImageList zu Beginn 15 leere Icons eingefügt. Klappt wunderbar. Da muss man aber auch erst mal drauf kommen. Wenn man nach dem Kommentar in der Virtualtrees.pas geht hat man die Unterscheidung ja deshalb gemacht, weil bei Indizes < 16 ein systeminternes Zeichnen verwendet wird das angeblich schneller wäre. Ich frage mich aber, ob das nun so ins Gewicht fällt.
Ich mache grundsätzlich keine Screenshots. Schießen auf Bildschirme gibt nämlich hässliche Pixelfehler und schadet der Gesundheit vom Kollegen gegenüber. I und E zu vertauschen hätte den selben negativen Effekt, würde aber eher dem Betriebsklima schaden
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#10

AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages

  Alt 21. Mär 2018, 09:36
Wenn man nach dem Kommentar in der Virtualtrees.pas geht hat man die Unterscheidung ja deshalb gemacht, weil bei Indizes < 16 ein systeminternes Zeichnen verwendet wird das angeblich schneller wäre. Ich frage mich aber, ob das nun so ins Gewicht fällt.
Ich frage mich, ob das überhaupt so funktioniert. Damit die Overlay-Funktionalität vom ImageList_DrawEx genutzt werden kann, muss dem entsprechenden Image in der ImageList auch erstmal ein Overlay-Index zugewiesen werden. Damit wird ein Mapping geschaffen zwischen dem Overlay-Index (0..14) und dem tatsächlichen Image-Index innerhalb der ImageList. Somit müssen die Overlays auch nicht zwingend am Anfang der ImageList liegen. Da das interne Overlay-Drawing aber nur mit einer ImageList arbeitet, müssen diese Overlays auch in derselben ImageList liegen, wie die normalen Icons.

Innerhalb des OnGetImageIndexEx-Events muss das dann natürlich beachtet werden (sobald der Bug in VTV behoben ist). Liegen die Overlays in derselben ImageList wie die anderen Icons ist der Overlay-Index zurückzugeben, andernfalls der ImageIndex. Das gilt dann auch für den Fall, daß mehr als 15 Overlays innerhalb dieser ImageList benötigt werden und das gewünschte Overlay nicht mehr als solches gemapt werden kann. Ich finde die aktuelle Implementierung ziemlich verwirrend und fehleranfällig.

Zitat von ImageList_DrawEx function:
An overlay image is drawn transparently over the primary image specified in the i parameter. To specify an overlay image in the fStyle parameter, use the INDEXTOOVERLAYMASK macro to shift the one-based index of the overlay image. Use the OR operator to logically combine the return value of the macro with the drawing style flags specified in the fStyle parameter. You must first specify this image as an overlay image by using the ImageList_SetOverlayImage function.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:32 Uhr.
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