![]() |
VirtualTreeView, OnGetImageIndexEx und OverlayImages
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:
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.
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; 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 |
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
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:
Das war mein Versuch eine ListView ähnlich dem Explorer nachzubasteln, primitiv ich weiss.
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; |
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
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.
|
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
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. |
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
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:
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.
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; |
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
Zitat:
Zitat:
Delphi-Quellcode:
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.
// If the user returned an index >= 15 then we cannot use the built-in overlay image drawing.
// Instead we do it manually. Zitat:
Delphi-Quellcode:
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.
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; |
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
Zitat:
Delphi-Quellcode:
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. |
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
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 :thumb: |
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
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.
|
AW: VirtualTreeView, OnGetImageIndexEx und OverlayImages
Zitat:
![]() 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:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:13 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz