< C++ .NET WinForm, Dialog Box & Controls 3 | Main | C++ .NET WinForm, Dialog Box & Controls 5 >


 

 

Windows Form, Dialog Boxes and More Controls 4

 

 

  1. Adding Directory Browsing

 

 

Adding Directory Browsing

 

Now that the TreeView has been set up, let’s make it display some useful information. Adding directory browsing capabilities will show you how to add nodes to the control and how to respond to TreeView events.

 

9.   Continue using the CppControls project you created in the previous exercise. Now that you know the TreeView displays correctly, use the property editor to remove the sample Root node.

 

TreeView control without root node in action

 

10. The first step in displaying directory information is to add a list of drive letters to the control, which you’ll need to do in the form source code. You’ll be using classes from the System::IO namespace, so add a using directive to the list at the top of the code, as shown here:

using namespace System::IO;

 

Adding System::IO namespace

 

 

 

 

 

 

11.     Add the following code to the end of the Form1 constructor after the call to InitializeComponent:

// get the logical drives

array<String^>^ drives = Directory::GetLogicalDrives();

 

for(int i=0; i<drives->Length; i++)

{

   String^ name = dynamic_cast<String^>(drives->GetValue(i));

   TreeNode^ tn = gcnew TreeNode(name);

   treeView1->Nodes->Add(tn);

   tn->Nodes->Add(gcnew TreeNode("<dummy>"));

}

 

Adding get the logical drives codes

 

The Directory class is one of the file system access classes provided in System::IO, and it has a number of static methods that help you work with directories. The first member of Directory that you’ll use is GetLogicalDrives, which returns an array of strings containing the names of all the logical drives. Note that the function returns a .NET managed array rather than a C++ native array, so you use the Count property to see how many elements the array contains and the get_Item method to access an element. Because get_Item returns a plain Object^, dynamic_cast is used to cast the pointer to a String^. In most cases, you ought to check the pointer returned by dynamic_cast at run time in case the cast has failed. Here we know that GetLogicalDrives always returns an array of Strings, so we are not expecting the cast ever to fail. We construct a new TreeNode for every item in the array, initialized with the drive name and added to the TreeView. By adding each TreeNode object directly to the TreeView, we are creating multiple root nodes, which is quite reasonable in this application. The final line of code adds one child element labeled <dummy> to each of the new nodes. You have seen tree controls showing the plus and minus signs, which you use to expand and collapse the tree. These signs aren’t displayed unless the TreeNode has child nodes. The problem is that we don’t want to create the child entries until the user clicks a plus sign, but the parent node doesn’t get a plus sign unless the child nodes are already in place. One quick and simple solution is to add a dummy child node. If coded correctly, the user will never see this node but the parent node will have a plus sign. When the user expands the node, the dummy node is deleted and replaced by the real child nodes.

 

12. If you build and run the code at this point, you should see the TreeView containing a list of the logical drives (depending how many drive you have on the machine that run this program), each of which has a plus sign next to it.

 

TreeView control with nodes in action

 

13. The obvious next step is to add another level of detail when the user clicks one of the plus signs. Looking at the table of events shown earlier, you’ll probably agree that the best event to handle is the BeforeExpand event, which is fired before a TreeNode is expanded. Use the Properties editor to add an event handler for the BeforeExpand event by double clicking an empty field next to the BeforeExpand property.

 

Adding BeforeExpand event

 

14.     Next, add the handler function source code like this:

private: System::Void treeView1_BeforeExpand(System::Object^  sender, System::Windows::Forms::TreeViewCancelEventArgs^  e)

{

   // First zap the dummy node, assuming there is one

   if (e->Node->Nodes->Count != 0)

         e->Node->Nodes->RemoveAt(0);

}

 

Adding BeforeExpand event handler source code

 

As usual, the function name reflects the control and the event, and the handler gets passed two arguments. Unlike the previous event handlers for buttons and menus that you’ve seen, this one gets passed a TreeViewCancelEventArgs object, which contains extra information about the event (specifically, the TreeNode that is about to be expanded). Before adding any child nodes to the tree, you need to remove the dummy node that was added to make the plus sign display. The Node property of the TreeViewCancelEventArgs object holds a pointer to the node that the event refers to. This node’s collection of children is accessed via the Nodes property, and an element can be removed by passing a zero-based index to the RemoveAt method. Before doing so, however, you need to check that there’s a node to be removed by checking the number of child nodes.

 

15.     Continue by adding the following code to display the contents of a directory:

private: System::Void treeView1_BeforeExpand(System::Object^  sender, System::Windows::Forms::TreeViewCancelEventArgs^  e)

{

      // First zap the dummy node, assuming there is one

      if (e->Node->Nodes->Count != 0)

            e->Node->Nodes->RemoveAt(0);

 

      // Get a list of subdirectories

      array<String^>^ dirs;

      try

      {

            dirs = Directory::GetDirectories(e->Node->FullPath);

      }

      catch(System::Exception^ pe)

      {

            MessageBox::Show(pe->Message, "Some Error!");

            return;

      }

 

      // Add a child node for each one

      for(int i=0; i<dirs->Length; i++)

      {

            String^ dirName = dynamic_cast<String^>(dirs->GetValue(i));

            TreeNode^ tn = gcnew TreeNode(Path::GetFileName(dirName));

            e->Node->Nodes->Add(tn);

            // Add a dummy child node

            tn->Nodes->Add(gcnew TreeNode("<dummy>"));

      }

}

 

Adding more BeforeExpand event handler codes

 

Given a path that points to a directory, the Directory::GetDirectories function returns an array of strings containing the names of all subdirectories. As before, this array is a managed array and not a native C++ array. The FullPath property of TreeNode returns a string that represents the path from the root to the node, and it does so by concatenating all the labels of the node’s parents, separated by a separator character. This path string is very useful when dealing with directory trees because if every label is a directory name and the separator character is a backslash (\), the full path to the directory can be built with very little trouble when the user expands a node. Note the try and catch blocks around the call to GetDirectories. What if you click the drive letter for a CD or a floppy drive that doesn’t contain a disk? GetDirectories will throw a “The device is not ready” exception, so you need to be prepared to catch it if you don’t want the program to fail. The for loop creates a TreeNode for every directory name and adds it as a child of the current node. The names returned by Directory::GetDirectories are full path names, but you don’t want to use the full path as a name. The Path::GetFileName will strip off everything up to (and including) the final backslash in a path, leaving only the directory name. Finally a dummy node is added to each child so that the plus sign will display properly. You can compile the application and test it, and you should be able to see all the directories on your drives. You can, of course, remove TreeNodes from the Nodes collection by using Remove. If you’re going to add or remove a lot of nodes at one time, consider using the BeginUpdate and EndUpdate functions to stop the control from redrawing itself every time the Nodes collection changes.

 

16.     Build and run the application. Expand the plus sign. If the drive that doesn’t contain a disk the “The device is not ready” message box will be displayed.

 

TreeView with directories in action

--------------------------------------------------------------

 

 

 

 

 

 

 

---------------------------------------------------------------

Device not ready message for the drives that don't have disks

 

The application works as it is, but let’s add images to the items in the tree to make it look more professional. To do so, you need to use an ImageList control. As its name implies, an ImageList is simply a control that manages a series of images, and it’s used by controls that might end up using a lot of images, such as TreeViews, ListViews, and ToolBars.

 

17.     Drag an ImageList control from the Toolbox onto the form, where it will appear in the section at the bottom of the designer reserved for non-graphical controls.

 

Adding visualcplusdotnetchap22List control to the TreeView control

 

18.  Select the ImageList, and then find the Images property in the Properties editor. Click the ellipses (...) button at the right side of the property to bring up the Image Collection Editor. Add the two bitmaps Folder.bmp and Folder_Open.bmp to the list. Set the image Size to 16, 16 (and make sure those image size also 16 x 16). We have created two not so small icons to represent open and closed folders by copying the icons somewhere; you can create your own or copy the bitmaps from the solution.

 

Adding visualcplusdotnetchap22s using visualcplusdotnetchap22s property

 

Adding and setting visualcplusdotnetchap22s properties through visualcplusdotnetchap22s Collection Editor

 

19. Now select the TreeView, and set the ImageList property to refer to the ImageList control. You also need to set the ImageIndex property to 0 or 1, depending on which entry represents the closed folder bitmap, to ensure that the correct bitmaps get used for open and closed folders. In this case we set the ImageIndex property to 0 (when the folder is snot selected) and the SelectedImageIndex property to 1 (when the folder is selected).

 

Setting Selectedvisualcplusdotnetchap22Index property to appropriate index value

 

20.     Build and run the application. You should see the tree being displayed with images.

 

TreeView with directories that having visualcplusdotnetchap22s attached

 

 

 

Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

 


 

< C++ .NET WinForm, Dialog Box & Controls 3 | Main | C++ .NET WinForm, Dialog Box & Controls 5 >