Problem with TShellTreeView lazarus / 31-LCL ---------------------------------------------------------------------- pusuni · 2015-08-16 12:01 Hi ! I'm trying to do a directory explorer with custom icons using TShellTreeViev , but I have a problem. The process: First, I created a TImagelist with four icons: Icon number 0: closed folder icon numbre 1: opened folder icon number 2: hidden  - closed folder and icon number 3: hiddden - opened folder After that, I added the following code to the  AdvancedCustomDrawItem  of the TshellTreeView: Code: [Select]procedure TForm1.ShellTreeView1AdvancedCustomDrawItem(Sender: TCustomTreeView;   Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;   var PaintImages, DefaultDraw: Boolean); begin   begin      case Node.Expanded of         TRUE:            if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then Node.ImageIndex :=3            else Node.ImageIndex :=1;         FALSE:            if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then Node.ImageIndex :=2            else Node.ImageIndex :=0;      end;   end; end; and the directory explorer seems to work correctly. I took two captures: http://fotos.subefotos.com/17a90577e858d72ea721c8bef2fd4f05o.jpg http://fotos.subefotos.com/1318c99fb027476c90f53bcee1e061aao.jpg but when I selected a directory ,  and the text is marked, the icon disappears. I took  another capture: http://fotos.subefotos.com/bff8a31adf99afe36487e97e86bde157o.jpg Anyone know what the problem is? Why doesn't it work properly? What's wrong with my code? Thanks in advanced ---------------------------------------------------------------------- howardpc · 2015-08-16 13:06 Perhaps the var parameter DefaultDraw needs to be set False? ---------------------------------------------------------------------- pusuni · 2015-08-16 14:51 Hi! I've tried and it haven't  fixed the issue. It worse. Code: [Select]procedure TForm1.ShellTreeView1AdvancedCustomDrawItem(Sender: TCustomTreeView;   Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;   var PaintImages, DefaultDraw: Boolean); begin   begin     DefaultDraw := FALSE;      case Node.Expanded of         TRUE:            if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then Node.ImageIndex :=3            else Node.ImageIndex :=1;         FALSE:            if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then Node.ImageIndex :=2            else Node.ImageIndex :=0;      end;   end; end; Result: http://subefotos.com/ver/?3f23e9327b2c147296d931d7277ed8a5o.jp g#codigos Code: [Select]procedure TForm1.ShellTreeView1AdvancedCustomDrawItem(Sender: TCustomTreeView;   Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;   var PaintImages, DefaultDraw: Boolean); begin   begin      case Node.Expanded of         TRUE:            if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then Node.ImageIndex :=3            else begin Node.ImageIndex :=1;     DefaultDraw := FALSE; end;          FALSE:            if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then Node.ImageIndex :=2            else Node.ImageIndex :=0;      end;   end; end; Result: http://subefotos.com/ver/?fe29025c4ebe452fd019ccec4060291co.jpg#codigo s Regards ---------------------------------------------------------------------- howardpc · 2015-08-16 16:36 It seems you have to do something rather hackish, such as the following (you will need to adapt this to your specific case): Code: [Select]implementation type   TCustomTreeViewAccess = class(TCustomTreeView); procedure TForm1.ShellTreeView1AdvancedCustomDrawItem(Sender: TCustomTreeView;   Node: TTreeNode; State: TCustomDrawState; Stage: TCustomDrawStage;   var PaintImages, DefaultDraw: Boolean); var   idx, indent: integer;   r: TRect;   function GetIconIndex: integer;   begin     case Node.Expanded of       True: if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then               Result:=3             else Result:=1;       False: if (FileGetAttr( ShellTreeView1.GetPathFromNode (node)) and faHidden) <> 0 then                Result:=2              else Result:=0;     end;   end; begin   idx:=GetIconIndex;   Node.ImageIndex:=idx;   PaintImages:=True;   DefaultDraw:=True;   if (cdsSelected in State) then     begin       DefaultDraw:=False;       r:=Node.DisplayRect(False);       indent:=TCustomTreeViewAccess(Sender).Indent;       imgList.Draw(Sender.Canvas, indent*Node.Level+indent, r.Top, idx, True);     end; end; ---------------------------------------------------------------------- pusuni · 2015-08-18 11:45 Hi howardpc! I don't know how I should use your PASCAL code. I've uploaded a test project with only two controls Could you modify this project with your code? Thanks in advanced ---------------------------------------------------------------------- howardpc · 2015-08-18 14:36 The altered project is attached with two components side-by-side so you can compare the two handlers written by you and me. The code I showed is not complete. It has various flaws, and does not paint some things correctly or completely. A correct solution would require a deeper understanding than I have of the the various painting stages (cdPrePaint, cdPostPaint, cdPreErase, cdPostErase) and drawing states (cdsSelected, cdsGrayed, cdsDisabled, dsChecked, cdsFocused, cdsDefault, cdsHot, cdsMarked, cdsIndeterminate) that the advanced handler uses. This would require you or me digging into the sources (which I do not have the time or motivation to do), or the skills of one of the developers who wrote the code. He could explain how to exploit it to do what you are after perfectly. Perhaps such a person will read this and be more help to you. ---------------------------------------------------------------------- wp · 2015-08-18 15:21 TShellTreeView is just a plain old TreeView which has a OnGetImageIndex and OnGetSelectedIndex event where an image index can be assigned to each node. I wonder why these events are not published. Forgotten? Anyway, here are instructions to get icons to each node without digging into the inner details of the treeview, and without a need for custom-drawing of the nodes: Load the ShellCtrls.pas (from lazarus\lcl) At the end of the declaration of TShellTreeview add: Code: [Select]  TShellTreeView = class(TCustomShellTreeView)   published     { TCustomTreeView properties }     property Align;     ....     property StateImages;   // <--- add     property OnGetImageIndex;   // <-- add     property OnGetSelectedIndex;  // <-- add   end; Save and recompile the ide (menu "Tools" / "Build Lazarus with..." After a while Lazarus will restart, and the TShellTreeView will have the new properties "StateImages" (not needed here), "OnGetImageIndex" and "OnGetselectedIndex". Add this event handler for "OnGetImageIndex" of the ShellTreeView: Code: [Select]procedure TForm1.ShellTreeView1GetImageIndex(Sender: TObject; Node: TTreeNode); var   path: String;   attr: LongInt; begin   path := ShellTreeView1.GetPathFromNode(node);   attr := FileGetAttr(path);   case Node.Expanded of     True : if (attr and (faHidden + faVolumeID + faSysFile)) = faHidden then  // extended to the the drive icons correct              Node.ImageIndex:=3 else              Node.ImageIndex:=1;     False: if (attr and (faHidden + faVolumeID + faSysFile)) = faHidden then              Node.ImageIndex:=2 else              Node.ImageIndex:=0;   end; end;  and add this event handler to "OnGetSelectedIndex": Code: [Select]procedure TForm1.ShellTreeView1GetSelectedIndex(Sender: TObject; Node: TTreeNode); begin   Node.SelectedIndex := Node.ImageIndex; end; And finally, if not already done, link the "Images" property of the Shelltreeview with the imagelist on the form. This is working here at Windows 7. If nobody disagrees here then I'll post a patch to add them to the official version. ---------------------------------------------------------------------- Bart · 2015-08-18 17:01 Quote from: wp on August 18, 2015, 05:21:54 pmIf nobody disagrees here then I'll post a patch to add them to the official version. Don't you have commit rights? Feel free to commit IMO, otherwise upload patch and assign to me. Bart ---------------------------------------------------------------------- wp · 2015-08-18 17:24 Quote from: Bart on August 18, 2015, 07:01:43 pmDon't you have commit rights? Only for "components". Uploaded a patch as issue #28539. ---------------------------------------------------------------------- wp · 2015-08-18 17:29 Quote from: pusuni on August 16, 2015, 02:01:28 pmbut when I selected a directory ,  and the text is marked, the icon disappears. This is because every node uses the "SelectedIndex" for selection of the image in the selected case. Your code only assigns the "node.ImageIndex" - just add "node.SelectedIndex := node.ImageIndex" and it should work. ---------------------------------------------------------------------- Bart · 2015-08-18 18:45 Quote from: wp on August 18, 2015, 07:24:05 pmQuote from: Bart on August 18, 2015, 07:01:43 pmDon't you have commit rights? Only for "components". Uploaded a patch as issue #28539. Thanks. Bart ---------------------------------------------------------------------- pusuni · 2015-08-19 06:24 Thanks very much at all. I fixed the issue with all this information. Best regards, pusuni ---------------------------------------------------------------------- pusuni · 2015-08-19 08:00 Quote from: wp on August 18, 2015, 07:29:50 pmQuote from: pusuni on August 16, 2015, 02:01:28 pmbut when I selected a directory ,  and the text is marked, the icon disappears. This is because every node uses the "SelectedIndex" for selection of the image in the selected case. Your code only assigns the "node.ImageIndex" - just add "node.SelectedIndex := node.ImageIndex" and it should work. Guau!! I've Added your code to mine: this is the most easy way to fix the problem!! Thank you very much ---------------------------------------------------------------------- Bart · 2015-08-19 09:13 Quote from: wp on August 18, 2015, 07:24:05 pm Uploaded a patch as issue #28539. Committed in r49686. Thanks. Bart ---------------------------------------------------------------------- pusuni · 2015-08-28 10:48 Hi again! I've found a new problem with the control: if I change the "FileSortType" property from the fstNone (it's the default value) to another value (fstAlphabet, for example) in Windows,  I get all the carpets duplicate. If I don't change the default value, all work properly. In Linux  there is not problem. I took two captures: http://fotos.subefotos.com/79168f486dc15c52d64a4fc6a2600fe7o.jpg http://fotos.subefotos.com/26f4e421d2ee1521c34390b4c5dafd06o.jpg Is it a bug? Thanks in advanced ---------------------------------------------------------------------- Bart · 2015-08-28 14:19 Reported in http://bugs.freepascal.org/view.php?id=28565 I'll look into it. Bart ---------------------------------------------------------------------- pusuni · 2015-08-29 16:39 Thanks a lot, Bart ---------------------------------------------------------------------- pusuni · 2015-09-20 09:04 Hi  - I think  - I found another bug in TShellTreeView control. When I do development in linux, the TShellTreeView.GetTextPath  gives right paths with / characters but in Windows, gives the same, when it should be \  I don't tested another similar controls, but I think , It's happens the same. Regards ---------------------------------------------------------------------- Bart · 2015-09-20 09:22 Use property Path instead. GetTextPath is just inherited from TTreeView and has a different meaning. Bart ---------------------------------------------------------------------- pusuni · 2015-09-20 09:55 Thanks, Bart