Ir al contenido



Foto

[RESUELTO] Treeview como explorer con checkboxes


  • Por favor identifícate para responder
52 respuestas en este tema

#1 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 12 febrero 2010 - 09:58

Hola foro aca les dejo un ejemplo de treeview como explorador con checkboxes aun no esta completo del todo pero lo dejo con dos objetivos ayudar al qu elo necesite y permitir que otros compañeros sigan enriqueciendolo sinmas el codigo
.cpp


cpp
  1. // ---------------------------------------------------------------------------
  2. #define NO_WIN32_LEAN_AND_MEAN
  3. #include <vcl.h>
  4. #pragma hdrstop
  5.  
  6. #include <shlobj.h>
  7. #include <shellapi.h>
  8. #include <stdio.h>
  9. #include <FileCtrl.hpp>
  10. #include <ComCtrls.hpp>
  11.  
  12. #include "Unit1.h"
  13. // ---------------------------------------------------------------------------
  14. #pragma package(smart_init)
  15.  
  16. #pragma resource "*.dfm"
  17. TForm1 *Form1;
  18.  
  19. TImageList *List;
  20. LPMALLOC mem;
  21. LPMALLOC pShellMalloc; // para SHGetMalloc
  22. // Estructura  para TDir
  23. typedef struct {
  24. LPSHELLFOLDER ParentShellFolder;
  25. LPITEMIDLIST pidl;
  26. LPITEMIDLIST ppidl;
  27. bool Sfogliato;
  28. }TDir;
  29.  
  30. // variables chkbox
  31. TTreeNode *ClickNode;
  32. bool NodeChecked;
  33.  
  34. // declaracion de la funcion chkbox
  35. void SetChildChecked(TTreeNode * ANode, bool yn);
  36.  
  37. // ---------------------------------------------------------------------------
  38. __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
  39. LPSHELLFOLDER desk;
  40. LPITEMIDLIST net;
  41. SHFILEINFO fi;
  42. STRRET nome;
  43. char scom[255];
  44. TTreeNode *n;
  45. TDir * d;
  46.  
  47. List = new TImageList(this);
  48. List->ShareImages = true;
  49. List->Handle = SHGetFileInfo("", 0, &fi, sizeof(SHFILEINFO),
  50. SHGFI_SMALLICON | SHGFI_SYSICONINDEX);
  51. TreeView->Images = List;
  52.  
  53. SHGetMalloc(&mem);
  54.  
  55. SHGetDesktopFolder(&desk);
  56.  
  57. // SHGetSpecialFolderLocation(NULL, CSIDL_NETWORK, &net);
  58. SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &net);
  59. desk->GetDisplayNameOf(net, SHGDN_NORMAL, &nome);
  60. GetNome(&nome, net, scom);
  61.  
  62. SHGetFileInfo((LPCSTR)net, 0, &fi, sizeof(SHFILEINFO),
  63. SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME | SHGFI_ATTRIBUTES | SHGFI_TYPENAME);
  64. n = TreeView->Items->Add(NULL, scom);
  65. n->ImageIndex = fi.iIcon;
  66. n->StateIndex = fi.iIcon;
  67. n->SelectedIndex = fi.iIcon;
  68. d = new TDir;
  69. d->ParentShellFolder = desk;
  70. d->pidl = net;
  71. d->ppidl = net;
  72. d->Sfogliato = true;
  73. n->Data = d;
  74.  
  75. BrowseFolder(desk, net, net, n);
  76.  
  77. SetWindowLong(TreeView->Handle,GWL_STYLE,
  78.   GetWindowLong(TreeView->Handle,GWL_STYLE)  |  TVS_CHECKBOXES);
  79.   SetWindowLong(TreeView->Handle,GWL_STYLE,
  80.   GetWindowLong(TreeView->Handle,GWL_STYLE)  |  TVS_CHECKBOXES);
  81. // // chkbox
  82. // SetWindowLong(TreeView->Handle, GWL_STYLE, GetWindowLong(TreeView->Handle,
  83. // GWL_STYLE) | TVS_CHECKBOXES);
  84.  
  85. }
  86.  
  87. // ---------------------------------------------------------------------------
  88. void __fastcall TForm1::GetNome(LPSTRRET nome, LPITEMIDLIST id, char * display)
  89. {
  90.  
  91. LPSTR lpsz;
  92. int cch;
  93.  
  94. switch(nome->uType) {
  95. case STRRET_WSTR:
  96. cch = WideCharToMultiByte(CP_ACP, 0, nome->pOleStr, -1, NULL, 0, NULL,
  97. NULL);
  98. lpsz = (LPSTR)mem->Alloc(cch);
  99. if (lpsz != NULL) {
  100. WideCharToMultiByte(CP_ACP, 0, nome->pOleStr, -1, lpsz, cch, NULL,
  101. NULL);
  102. sprintf(display, "%s", lpsz);
  103. mem->Free(lpsz);
  104. }
  105. break;
  106.  
  107. case STRRET_OFFSET:
  108. sprintf(display, "%s", ((char*)id) + nome->uOffset);
  109. break;
  110.  
  111. case STRRET_CSTR:
  112. sprintf(display, "%s", nome->cStr);
  113. break;
  114. }
  115. }
  116.  
  117. // ----------------
  118. LPITEMIDLIST __fastcall TForm1::MergeIDList(LPITEMIDLIST a, LPITEMIDLIST b) {
  119. int cb1, cb2;
  120.  
  121. if (a)
  122. cb1 = GetPIDLSize(a);
  123. if (cb1)
  124. cb1 = cb1 - 2;
  125.  
  126. if (b)
  127. cb2 = GetPIDLSize(b);
  128. if (cb2)
  129. cb2 = cb2 - 2;
  130.  
  131. int total_size = cb1 + cb2 + 2;
  132.  
  133. LPITEMIDLIST lpidlNew;
  134.  
  135. if (!a || !b)
  136. return NULL;
  137. lpidlNew = (LPITEMIDLIST)mem->Alloc(total_size);
  138. if (lpidlNew) {
  139. ZeroMemory(lpidlNew, total_size);
  140. CopyMemory(lpidlNew, a, cb1);
  141. CopyMemory(((LPBYTE)lpidlNew) + cb1, b, cb2);
  142. FillMemory(((LPBYTE)lpidlNew) + cb1 + cb2, 2, 0);
  143. return lpidlNew;
  144. }
  145. return NULL;
  146.  
  147. }
  148.  
  149. // ------------------
  150. void __fastcall TForm1::BrowseFolder(LPSHELLFOLDER padre, LPITEMIDLIST pidl,
  151. LPITEMIDLIST ppidl, TTreeNode *nodo) {
  152. TTreeNode *c;
  153. if (nodo != NULL) {
  154. while (nodo->Count > 0)
  155. nodo->Item[0]->Delete();
  156. }
  157. if (padre != NULL) {
  158. LPSHELLFOLDER ShellFolder = NULL;
  159.  
  160. padre->BindToObject(pidl, NULL, IID_IShellFolder, (void**)
  161. & ShellFolder);
  162. if (ShellFolder != NULL) {
  163. LPENUMIDLIST enumlist = NULL;
  164.  
  165. ShellFolder->EnumObjects(NULL,
  166. SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN, &enumlist);
  167.  
  168. if (enumlist != NULL) {
  169. int i;
  170. LPSTRRET nome;
  171. LPITEMIDLIST idfiglio;
  172. LPITEMIDLIST pp;
  173. char scom[255];
  174. SHFILEINFO fi;
  175. TDir *d;
  176. int r;
  177. int conta1, conta2;
  178.  
  179. enumlist->Reset();
  180. while (enumlist->Next(1, &idfiglio, NULL) != S_FALSE) {
  181. LPITEMIDLIST lpNew = MergeIDList(ppidl, idfiglio);
  182. if (!idfiglio)
  183. break;
  184. if (lpNew == NULL)
  185. continue;
  186. nome = (LPSTRRET)mem->Alloc(sizeof(STRRET));
  187.  
  188. memset(&fi, 0, sizeof(SHFILEINFO));
  189.  
  190. r = SHGetFileInfo((LPCSTR)lpNew, 0, &fi, sizeof(fi),
  191. SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME |
  192. SHGFI_ATTRIBUTES | SHGFI_TYPENAME | SHGFI_SMALLICON);
  193.  
  194. ZeroMemory(nome, sizeof(STRRET));
  195. nome->uType = STRRET_CSTR;
  196. ShellFolder->GetDisplayNameOf(idfiglio, SHGDN_NORMAL, nome);
  197. GetNome(nome, idfiglio, scom);
  198.  
  199. c = TreeView->Items->AddChild(nodo, scom);
  200. c->ImageIndex = fi.iIcon;
  201. c->StateIndex = fi.iIcon;
  202. c->SelectedIndex = fi.iIcon;
  203.  
  204. // Cre elelemnto fittizio
  205. //originalmente decia TreeView->Items->AddChild(c, "PP");
  206.  
  207. if (fi.dwAttributes & SFGAO_HASSUBFOLDER)
  208. TreeView->Items->AddChild(c, "");
  209.  
  210. d = new TDir;
  211. d->ParentShellFolder = ShellFolder;
  212. d->pidl = idfiglio;
  213. d->ppidl = lpNew;
  214. d->Sfogliato = false;
  215. c->Data = d;
  216. }
  217. enumlist->Release();
  218.  
  219. }
  220. }
  221. }
  222.  
  223. }
  224.  
  225. // -----------
  226. int __fastcall TForm1::GetPIDLSize(LPITEMIDLIST lpidl) {
  227. unsigned short cb = 0;
  228. while (lpidl) {
  229. cb = (unsigned short)(cb + lpidl->mkid.cb);
  230. lpidl = GetNextItem(lpidl);
  231. }
  232. return(unsigned short)(cb + 2);
  233.  
  234. }
  235.  
  236. // ------------
  237. LPITEMIDLIST __fastcall TForm1::GetNextItem(LPITEMIDLIST pidl) {
  238. unsigned short nLen = pidl->mkid.cb;
  239. if (nLen == 0)
  240. return NULL;
  241. return(LPITEMIDLIST)((LPBYTE)pidl + nLen);
  242.  
  243. }
  244.  
  245. // --------------
  246. void __fastcall TForm1::TreeViewExpanding
  247. (TObject *Sender, TTreeNode *Node, bool &AllowExpansion) {
  248. TDir *d;
  249.  
  250. if (Node != NULL) {
  251. d = (TDir*)Node->Data;
  252. if (!d->Sfogliato) {
  253. BrowseFolder(d->ParentShellFolder, d->pidl, d->ppidl, Node);
  254. }
  255. d->Sfogliato = true;
  256. }
  257. //ok para mostar checbox
  258.     SetChildChecked(ClickNode, NodeChecked);
  259. }
  260.  
  261. // ---------------------------------------------------------------------------
  262. void __fastcall TForm1::TreeViewClick(TObject *Sender) {
  263. TDir *d;
  264. if (TreeView->Selected) {
  265. char scom[MAX_PATH];
  266. d = (TDir*)(TreeView->Selected->Data);
  267.  
  268. SHGetPathFromIDList(d->ppidl, scom);
  269. Label1->Caption = scom;
  270. }
  271.  
  272. }
  273.  
  274. // ---------------------------------------------------------------------------
  275. // funcioneschkbox
  276. bool GetNodeChecked(TTreeNode *ANode) {
  277. TVITEM tvItem;
  278. tvItem.mask = TVIF_HANDLE | TVIF_STATE;
  279. tvItem.hItem = ANode->ItemId;
  280. tvItem.stateMask = TVIS_STATEIMAGEMASK;
  281. TreeView_GetItem(ANode->TreeView->Handle, &tvItem);
  282. return((BOOL)(tvItem.state >> 12) - 1);
  283. }
  284.  
  285. // -----------
  286. void SetNodeChecked(TTreeNode *ANode, bool IsSetToChecked) {
  287. TVITEM tvItem;
  288. tvItem.mask = TVIF_HANDLE | TVIF_STATE;
  289. tvItem.hItem = ANode->ItemId;
  290. tvItem.stateMask = TVIS_STATEIMAGEMASK;
  291. tvItem.state = INDEXTOSTATEIMAGEMASK(IsSetToChecked ? 2 : 1);
  292. TreeView_SetItem(ANode->TreeView->Handle, &tvItem);
  293. }
  294.  
  295. // --------------
  296. void SetChildChecked(TTreeNode *ANode, bool yn) {
  297. int count = ANode->Count;
  298. SetNodeChecked(ANode, yn);
  299. if (count != 0)
  300. for (int i = 0; i < count; i++)
  301. SetChildChecked(ANode->Item[i], yn);
  302.  
  303. }
  304.  
  305. // ----------
  306. void __fastcall TForm1::TreeViewMouseDown(TObject *Sender, TMouseButton Button,
  307. TShiftState Shift, int X, int Y) {
  308. if (ClickNode != NULL)
  309. if (GetNodeChecked(ClickNode) != NodeChecked) {
  310. NodeChecked = !NodeChecked;
  311. SetChildChecked(ClickNode, NodeChecked);
  312. }
  313.  
  314. }
  315. // ---------------------------------------------------------------------------
  316.  
  317. void __fastcall TForm1::TreeViewMouseMove(TObject *Sender, TShiftState Shift,
  318. int X, int Y) {
  319. ClickNode = TreeView->GetNodeAt(X, Y);
  320. if (ClickNode != NULL)
  321. NodeChecked = GetNodeChecked(ClickNode);
  322.  
  323. }
  324. // ---------------------------------------------------------------------------
  325.  
  326.  
  327. void __fastcall TForm1::Button1Click(TObject *Sender)
  328. {
  329. Memo1->Clear();
  330.   for (int i=0 ; i<TreeView->Items->Count; i++)
  331. if (GetNodeChecked(TreeView->Items->Item[i])&&
  332. !TreeView->Items->Item[i]->Text.IsEmpty()){
  333.   Memo1->Lines->Add(TreeView->Items->Item[i]->Text);
  334.  
  335. }
  336. }
  337. //---------------------------------------------------------------------------



.h


cpp
  1. //---------------------------------------------------------------------------
  2.  
  3. #ifndef Unit1H
  4. #define Unit1H
  5. //---------------------------------------------------------------------------
  6. #include <Classes.hpp>
  7. #include <Controls.hpp>
  8. #include <StdCtrls.hpp>
  9. #include <Forms.hpp>
  10.  
  11. #include <ComCtrls.hpp>
  12. //---------------------------------------------------------------------------
  13. class TForm1 : public TForm
  14. {
  15. __published: // IDE-managed Components
  16. TLabel *Label1;
  17. TTreeView *TreeView;
  18. TMemo *Memo1;
  19. TButton *Button1;
  20. void __fastcall TreeViewExpanding(TObject *Sender, TTreeNode *Node, bool &AllowExpansion);
  21. void __fastcall TreeViewClick(TObject *Sender);
  22. void __fastcall TreeViewMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
  23.   int X, int Y);
  24. void __fastcall TreeViewMouseMove(TObject *Sender, TShiftState Shift, int X, int Y);
  25. void __fastcall Button1Click(TObject *Sender);
  26.  
  27.  
  28. private: // User declarations
  29.  
  30. void __fastcall GetNome(LPSTRRET nome, LPITEMIDLIST id, char *display);
  31.   void __fastcall BrowseFolder(LPSHELLFOLDER padre, LPITEMIDLIST pidl,
  32.   LPITEMIDLIST ppidl, TTreeNode *nodo);
  33.   LPITEMIDLIST __fastcall MergeIDList(LPITEMIDLIST a, LPITEMIDLIST b);
  34.   int __fastcall GetPIDLSize(LPITEMIDLIST lpidl);
  35.   LPITEMIDLIST __fastcall GetNextItem(LPITEMIDLIST pidl);
  36. public: // User declarations
  37. __fastcall TForm1(TComponent* Owner);
  38. };
  39. //---------------------------------------------------------------------------
  40. extern PACKAGE TForm1 *Form1;
  41. //---------------------------------------------------------------------------
  42. #endif


  • 0

#2 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 12 febrero 2010 - 10:04

Gracias por el aporte compañero (y) y bienvenido al foro, estoy seguro que habrán compañeros que lo mejorarán si se da el caso, de nuevo te reitero la bienvenida ;)

Saludos.
  • 0

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.966 mensajes
  • LocationMéxico

Escrito 12 febrero 2010 - 10:24

Bienvenido a DelphiAccess ifrit

Muchas gracias por tu aportación y espero que te sientas como en casa y sobre todo entre amigos.

Salud OS
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 12 febrero 2010 - 10:36

Bienvenido a delphiaccess ifrit. Gracias por tu interesante código.  (y)

Cuando tenga un rato lo miraré mas despacio.

Saludos.
  • 0

#5 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 13 febrero 2010 - 04:34

He revisado el código y aunque no entiendo el fin que se le va a dar, intuyo que se trata de una especie de sistema para elegir un conjunto de ficheros de varias carpetas.

Hecho en falta las elecciones parciales de carpetas y que estas sean automáticas con respecto a las subcarpetas elegidas.

La salida en un memo no me parece lo mejor, quizás en un TListView sería mas apropiado. Además permitiría la elección de ficheros específicos.

Me he permitido modificar algo el código implementando:
1.-  ChecBox en estado disable, PartialCheck, UnCheck, Check y sin uso.
2.-  Automatización de los CheckBox.
3.-  Rutina de encontrar ficheros en carpetas y subcarpetas .

El Volcado de los archivos de las carpetas checkeadas total o parcialmente lo mantengo en el TMemo, pero ya comente sobre la posibilidad de otro control.

La rutina de exploración de carpetas es esta:



cpp
  1. void ListaDir(String Dir, TStrings* Strings, bool SubDir = false)
  2. {
  3.     if(Dir=="") return;
  4.     TSearchRec sr;
  5.     if(!FindFirst(Dir + "\\*.*", faAnyFile, sr))
  6.     do{
  7.       Application->ProcessMessages();
  8.       if(sr.Name != "." && sr.Name != ".."){
  9.           if(sr.Attr & faDirectory){
  10.             if(SubDir) ListaDir(Dir + "\\" + sr.Name, Strings, true);
  11.           }else
  12.             Strings->Add(Dir + "\\" + sr.Name);
  13.       }
  14.     } while (!FindNext(sr));
  15.     FindClose(sr);
  16. }



La rutina de respuesta a la pulsación del botón queda así:


cpp
  1. void __fastcall TForm1::Button1Click(TObject *Sender)
  2. {
  3.   Memo1->Clear();
  4.   char Path[MAX_PATH];
  5.   TDir* Dir;
  6.   for(int i=0 ; i<TreeView->Items->Count; i++){
  7.     if(!TreeView->Items->Item[i]->Text.IsEmpty()){
  8.       Dir = (TDir*)(TreeView->Items->Item[i]->Data);
  9.       SHGetPathFromIDList(Dir->ppidl, Path);
  10.       if(TreeView->Items->Item[i]->StateIndex == Checked && *Path)
  11.         ListaDir(Path, Memo1->Lines, true);
  12.       else if(TreeView->Items->Item[i]->StateIndex == PartialChecked && *Path)
  13.         ListaDir(Path, Memo1->Lines);
  14.     }
  15.   }
  16. }



Adjunto el código completo. Ese código es un ejemplo de como continuar el desarrollo dando las bases para ello.


Edito: He corregido un bug en SetParentState


Saludos.

Archivos adjuntos


  • 0

#6 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 15 febrero 2010 - 06:08

hola escafandra y amigos del foro, muchas gracias por la bienvenida al foro, se que es de delphi mayormente, pero es bueno saber que tienen un espacio abierto al c++ y a muchos otros lenguajes.... (y)
escafandra, el objetivo es hacer un sistema de salvas como el del ntbackup del propio windows, o como el del nero o el del titanbackup de gfi, yo creo y he estado dandole vueltas al asunto que esta es la mejor forma de seleccionar ficheros a la hora de hacer salvas (de todos modos si hay alguna discrepancia o sugerencia, sin problemas la escucho)..El memo, no ira. De echo no abra ningun componente recepcionando los ficheros seleccionados, sino que estos iran a una base de datos en access (por el momento, he tenido la idea de hacerlo con una base de datos portable pero no se cual, no por tener muchas opciones , sino que no conozco ninguna, aunque ya he visto un sin fin de aplicaciones que los datos los guardan en ficheros .dat, pero para ser sincero no se cuales bd utilizan :s)
Ya probare el codigo que muy agradecido descargue, en cuanto lo prueve te dejo saber y asi enriquecemso este post...Muchas gracias amigo, de veras que si.
Un saludo.
  • 0

#7 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 15 febrero 2010 - 06:24

Hola escafandra, aun no prueve a compilar el codigo fastidiosamente el bcb 2010 se me dio lios al querer ponerle un update y tuve que desintalarlo, pero si pude ver el .exe que me dejas pues estoy muy contento y en realidad no sabria como agradecerte, mira si te digo que he estado detras de poder hacer esto mas de un mes seria poco, he luchado con paginas en japones y demas....Bueno amigo , muchas gracias, cualquier otra duda espero que estes por aqui para seguir debatiendo.Muchas gracias y mis respetos
  • 0

#8 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 15 febrero 2010 - 06:34

Me alegra que tu búsqueda hasta por el Japón haya tenido un buen término en Delphiaccess.  (y)  :D.

Pro error dejé dos link del ejemplo, uno de ellos tiene un pequeño bug que quizás no notes  :^). El caso es que colgué el ejemplo corregido y me olvidé de retirar en antiguo. El que aparece ahora es el correcto.

En cuanto a tu base de datos portable, si lo que quieres es guardar carpetas de archivos completas, lo ideal es que utilices un sistema de compresión y guardes el archivo comprimido con la información de como descomprimir y las carpetas donde deben ir. No veo la necesidad de utilizar bases de datos.

Repito, se bienvenido en el foro, cosa que a estas alturas ya has notado.  :p

Saludos.
  • 0

#9 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 15 febrero 2010 - 04:17

Tras una observación de ifrit de un comportamiento anómalo del explorador, he revisado la función SetParentState que tenía un diseño recursivo complejo y la he cambiado a no recursiva y mas simple. Para ello he realizado algún cambio más en otras funciones que facilitan la tarea.

Dejo el nuevo enlace.

Saludos.
  • 0

#10 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 16 febrero 2010 - 05:27

Una vuelta de tuerca mas.

El ifrit parece querer realizar un sistema de selección de archivos sin controles añadidos al TTreeView. Bien, el código que propongo en esta ocasión incorpora al árbol las carpetas, subcarpetas y archivos. Éstos últimos se colocan al final de las carpetas de cada rama y tienen sus correspondientes checkboxs. Los archivos seleccionados se muestran en un TMemo que sólo tiene la función de mostrar la lista... Se podría sustituir por un TStringList.

La base del efecto está aquí:


cpp
  1. typedef struct {
  2. LPSHELLFOLDER ParentShellFolder;
  3. LPITEMIDLIST pidl;
  4. LPITEMIDLIST ppidl;
  5. bool Sfogliato;
  6.         bool File;
  7. }TDir;
  8.  
  9. //------------------------------------------------------------------------------
  10. void __fastcall TForm1::BrowseFolder(LPSHELLFOLDER padre, LPITEMIDLIST pidl,
  11. LPITEMIDLIST ppidl, TTreeNode *nodo)
  12. {
  13.   TTreeNode *c;
  14.   TTreeNode *FirtsFile = 0;
  15.   if(nodo != NULL) {
  16.     while (nodo->Count > 0)
  17.         nodo->Item[0]->Delete();
  18.   }
  19.   if(padre != NULL) {
  20.     LPSHELLFOLDER ShellFolder = NULL;
  21.  
  22.     padre->BindToObject(pidl, NULL, IID_IShellFolder, (void**) & ShellFolder);
  23.     if(ShellFolder != NULL){
  24.       LPENUMIDLIST enumlist = NULL;
  25.       ShellFolder->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN | SHCONTF_NONFOLDERS, &enumlist);
  26.       if(enumlist != NULL) {
  27.           int i;
  28.           LPSTRRET nome;
  29.           LPITEMIDLIST idfiglio;
  30.           LPITEMIDLIST pp;
  31.           char scom[255];
  32.           SHFILEINFO fi;
  33.           TDir *d;
  34.           int r;
  35.           int conta1, conta2;
  36.           enumlist->Reset();
  37.           while (enumlist->Next(1, &idfiglio, NULL) != S_FALSE) {
  38.             LPITEMIDLIST lpNew = MergeIDList(ppidl, idfiglio);
  39.             if (!idfiglio)
  40.                 break;
  41.             if (lpNew == NULL)
  42.                 continue;
  43.             nome = (LPSTRRET)mem->Alloc(sizeof(STRRET));
  44.             memset(&fi, 0, sizeof(SHFILEINFO));
  45.             r = SHGetFileInfo((LPCSTR)lpNew, 0, &fi, sizeof(fi),
  46.                                 SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME |
  47.                                 SHGFI_ATTRIBUTES | SHGFI_TYPENAME | SHGFI_SMALLICON);
  48.  
  49.             ZeroMemory(nome, sizeof(STRRET));
  50.             nome->uType = STRRET_CSTR;
  51.             ShellFolder->GetDisplayNameOf(idfiglio, SHGDN_NORMAL, nome);
  52.             GetNome(nome, idfiglio, scom);
  53.  
  54.             // Los archivos se colocan al final de las carpetas
  55.             if(nodo->Level < 1)
  56.               c = TreeView->Items->AddChild(nodo, scom);
  57.             else{
  58.               // Si es un fichero
  59.               if(!(fi.dwAttributes & SFGAO_FOLDER)){
  60.                 c = TreeView->Items->AddChild(nodo, scom);
  61.                 if(!FirtsFile) FirtsFile = c;
  62.               }
  63.               // Si es una carpeta
  64.               else{
  65.                 if(FirtsFile)
  66.                   c = TreeView->Items->Insert(FirtsFile, scom);
  67.                 else
  68.                   c = TreeView->Items->AddChild(nodo, scom);
  69.               }
  70.             }
  71.             c->ImageIndex = fi.iIcon;
  72.             c->StateIndex = fi.iIcon;
  73.             c->SelectedIndex = fi.iIcon;
  74.             c->StateIndex = 1;
  75.  
  76. //            if (fi.dwAttributes & SFGAO_HASSUBFOLDER)
  77.             if ((fi.dwAttributes & SFGAO_FOLDER) || (fi.dwAttributes & SFGAO_HASSUBFOLDER))
  78.               TreeView->Items->AddChild(c, "");
  79.  
  80.             d = new TDir;
  81.             d->ParentShellFolder = ShellFolder;
  82.             d->pidl = idfiglio;
  83.             d->ppidl = lpNew;
  84.             d->Sfogliato = false;
  85.             d->File = false;
  86.             // Si es un fichero
  87.             if(!(fi.dwAttributes & SFGAO_FOLDER))
  88.                 d->File = true;
  89.             c->Data = d;
  90.           }
  91.           enumlist->Release();
  92.       }
  93.     }
  94.   }
  95. }



Y la lista se consigue así:


cpp
  1. void __fastcall TForm1::Button1Click(TObject *Sender)
  2. {
  3.   Memo1->Clear();
  4.   char Path[MAX_PATH];
  5.   TDir* Dir;
  6.   for(int i=0 ; i<TreeView->Items->Count; i++){
  7.     if(!TreeView->Items->Item[i]->Text.IsEmpty()){
  8.       Dir = (TDir*)(TreeView->Items->Item[i]->Data);
  9.       SHGetPathFromIDList(Dir->ppidl, Path);
  10.       if(TreeView->Items->Item[i]->StateIndex == Checked && *Path && !Dir->File)
  11.         ListaDir(Path, Memo1->Lines, true);
  12.       else if(TreeView->Items->Item[i]->StateIndex == Checked && *Path && Dir->File)
  13.         Memo1->Lines->Add(String(Path));
  14.     }
  15.   }
  16. }




Dejo colgado el código con un ejecutable compilado.

Saludos.

Archivos adjuntos


  • 0

#11 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.966 mensajes
  • LocationMéxico

Escrito 16 febrero 2010 - 05:33

Que bien está eso amigo (y)

Salud OS
  • 0

#12 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 16 febrero 2010 - 05:36

Que bien está eso amigo (y)...


¿Ya lo has probado? ¡Qué velocidad! :o :D

Saludos.
  • 0

#13 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.966 mensajes
  • LocationMéxico

Escrito 16 febrero 2010 - 05:44


Que bien está eso amigo (y)...


¿Ya lo has probado? ¡Qué velocidad! :o :D

Saludos.


:D :D :D

Si amigo, solo un detalle mínimo, si deseas cancelar no responde, imagino que está en el loop y hace caso omiso a cualquier evento. :)

Salud OS
  • 0

#14 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 16 febrero 2010 - 05:57

...solo un detalle mínimo, si deseas cancelar no responde, imagino que está en el loop y hace caso omiso a cualquier evento. :)


Cierto, el bucle del código de respuesta a la pulsación del botón no tiene un Application->ProcessMessages(); que facilitaría esa tarea. Aunque habría que añadir algún que otro filtro para evitar la reentrada en dicho evento...  El propósito no era mostrar eso, sino una propuesta de solución al problema que nos ha presentado ifrit.

Tampoco está previsto la actualización si hubiese un cambio en la estructura del árbol de directorios del disco X mientras trabajamos...

Saludos.
  • 0

#15 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.966 mensajes
  • LocationMéxico

Escrito 16 febrero 2010 - 06:00


...solo un detalle mínimo, si deseas cancelar no responde, imagino que está en el loop y hace caso omiso a cualquier evento. :)


Cierto, el bucle del código de respuesta a la pulsación del botón no tiene un Application->ProcessMessages(); que facilitaría esa tarea. Aunque habría que añadir algún que otro filtro para evitar la reentrada en dicho evento...  El propósito no era mostrar eso, sino una propuesta de solución al problema que nos ha presentado ifrit.

Tampoco está previsto la actualización si hubiese un cambio en la estructura del árbol de directorios del disco X mientras trabajamos...

Saludos.


Bueno, no lo he dicho como si hubiese encontrado un bug que para eso tengo suficiente con mis desarrollos que están plagados de ellos :D :D :D

Lo dicho, es un excelente trabajo amigo :)

Salud OS
  • 0

#16 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 16 febrero 2010 - 06:07

...Bueno, no lo he dicho como si hubiese encontrado un bug que para eso tengo suficiente con mis desarrollos que están plagados de ellos :D :D :D...


Ni yo lo he considerado así  :D, pero no sería extraño que surgiese alguno... :p Y si así fuese, mejor, pues sólo se corrige el bug conocido.  :D.

Gracias a ti.

Saludos.


  • 0

#17 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 17 febrero 2010 - 05:52

:shocked: Me haz dejado pasmado....
escafandra, que barbaridad de ejemplo nos has facilitado y en que poco tiempo, para serte sincero no esperaba que la ayuda fuese tanta,  no se como agradecrete la atencion con mi tema, todo va viento en popa, se que muchos te lo agradeceremos y te repito aun estuve buscando en varias paginas (japonesas porque traen mas de este tema que otras ) con el objetivo de no atormentarte tanto con el tema y nada encontre por alla..Amigo muchas gracias y tremendisimo aporte a mi  y a la comunnidad
mis saludos y respetos


  • 0

#18 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 23 febrero 2010 - 08:50

Hola escafandra, tengo un detalle que no logro resolver, cuando selecciono, por ejemplo, F y luego le doy clic al bootn para pasar sus carpetas y archivos al memo, este no me pasa nada, sin embargo cuando despliego las carpetas y ficheros si me pasa los valores al memo, existe alguna forma de sin estar desplegada la unidad fisica o carpeta padre se pasen todos sus valores (subcarpetas y ficheros al memo)?
gracias y saludos
  • 0

#19 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 23 febrero 2010 - 02:33

...cuando selecciono, por ejemplo, F y luego le doy clic al bootn para pasar sus carpetas y archivos al memo, este no me pasa nada...


Bueno, en los ejemplos que yo tengo, eso no me sucede. Habrá que ver que "refrito" estas usando tu  :p  :D

Cambiando un poco de tema, el último ejemplo carecía de dos cosas fundamentales para un programa funcional:

...solo un detalle mínimo, si deseas cancelar no responde, imagino que está en el loop y hace caso omiso a cualquier evento. :)


y otro no menos importante:

...Tampoco está previsto la actualización si hubiese un cambio en la estructura del árbol de directorios del disco X mientras trabajamos...


Bueno, te propongo una solución para ambos supuestos con lo que conseguimos mayor profesionalidad:

En el primer caso, la acción de la selección se interrumpe si hacemos Click en el TreeView (podría hacerse de otra manera si así lo queremos).

Para el segundo caso tenemos que complicarnos algo mas. El truco para sensibilizar la aplicación a los cambios producidos en el Shell, se basa en la API SHChangeNotifyRegister. Con esta API registramos nuestra aplicación como receptora de mensajes dirigidos al Shell para notificar de los cambios que le puedan afectar (SHChangeNotify). Se incluyen la inserción de memorias USB. El resto del trabajo será el tratamiento de esos mensajes:



cpp
  1. //---------------------------------------------------------------------------
  2. void __fastcall TForm1::StartNotification()
  3. {
  4.     PSHChangeNotifyRegister SHChangeNotifyRegister =
  5.           (PSHChangeNotifyRegister)GetProcAddress(GetModuleHandle("shell32.dll"), "SHChangeNotifyRegister");
  6.  
  7.     SHChangeNotifyEntry shCNE;
  8.     shCNE.pidl = 0;
  9.     shCNE.fRecursive = TRUE;
  10.  
  11.     // Eventos que se van a registrar
  12.     LONG Events = SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_DRIVEADD |
  13.                   SHCNE_DRIVEREMOVED | SHCNE_UPDATEDIR | SHCNE_UPDATEITEM |
  14.                   SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_MKDIR | SHCNE_RMDIR |
  15.                   SHCNE_CREATE |SHCNE_DELETE;
  16.  
  17.     m_ulSHChangeNotifyRegister = SHChangeNotifyRegister(Handle, SHCNRF_INTERRUPT_LEVEL | SHCNRF_SHELL_LEVEL, Events, WM_USER_SHELLCHANGED, 1, &shCNE);
  18. }
  19.  
  20. //---------------------------------------------------------------------------
  21. void __fastcall TForm1::WndProc(Messages::TMessage &Message)
  22. {
  23.   if(Message.Msg == WM_USER_SHELLCHANGED){
  24.     //  AbsoluteIdl[0] =  the previous PIDL or name of the folder.
  25.     //  AbsoluteIdl[0] =  the new PIDL or name of the folder.
  26.     LPITEMIDLIST *AbsoluteIdl = (LPITEMIDLIST*)Message.WParam;
  27.     char Path[MAX_PATH];
  28.     TTreeNode* Node;
  29.     TTreeNode* newNode;
  30.     TDir *d;
  31.     switch(Message.LParam & 0x7FFFFFF)
  32.     {
  33.       case SHCNE_CREATE:
  34.       case SHCNE_MKDIR:
  35.         AddNode(AbsoluteIdl[0]);
  36.       break;
  37.  
  38.       case SHCNE_DELETE:
  39.       case SHCNE_RMDIR:
  40.         Node = Search(AbsoluteIdl[0]);
  41.         if(Node && GetLevel(AbsoluteIdl[0])>1)
  42.             TreeView->Items->Delete(Node);
  43.       break;
  44.  
  45.       case SHCNE_RENAMEFOLDER:
  46.       case SHCNE_RENAMEITEM:
  47.         Node = Search(AbsoluteIdl[0]);
  48.         if(Node && GetLevel(AbsoluteIdl[0])>1)
  49.             TreeView->Items->Delete(Node);
  50.         AddNode(AbsoluteIdl[1]);
  51.       break;
  52.  
  53.       case SHCNE_DRIVEADD:
  54.         AddNode(AbsoluteIdl[0], TreeView->Items->Item[0]);
  55.       break;
  56.  
  57.       case SHCNE_DRIVEREMOVED:
  58.         Node = Search(AbsoluteIdl[0]);
  59.         if(Node){
  60.           SetState(Node, UnChecked);
  61.           TreeView->Items->Delete(Node);
  62.         } 
  63.     }
  64.   }
  65.  
  66.   TForm::WndProc(Message);
  67. }



Aprovecho para optimizar algo mas el código, pues muchas cosas son superfluas.

El ejemplo que subo selecciona todos los archivos de una unidad sin necesidad de desplegarla entera, sólo con marcarla.


Saludos.


PD: Descarga
  • 0

#20 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 02 marzo 2010 - 05:47

Hola escafandra, no habia tenido la oportunidad de agracederte por el esfuerzo y la atencion que le pusistes al tema desde el primer momento, realmente estoy muy agradecido por todo, no creo que se le pueda pedirm mas al codigo que haz dejado
infinitas gracias

  • 0