Topic : MFC - Views
Author : Unknown
Page : << Previous 3  Next >>
Go to page :

Wizard does have a choice to let us create splitter window, however, it can only help us with creating dynamic splitter window. We can modify the dynamic splitter window to static splitter window after the application is generated. To let the Application Wizard generate code for implementing dynamic splitter window, we can click "Advanced..." button (in step 4) and check "Use split widow" check box in the popped up dialog box.

In order to create a splitter window with two panes implemented by different types of views, first we must implement two view classes. Here, one of the views can be implemented as we go through the Application Wizard's project creation steps: in the final step, we can select CListView as the view's base class. The other class can be added after the project is generated by Class Wizard.

Sample 3\Explorer is created this way. It is a standard SDI application, with first view generated by Application Wizard whose name is CExplorerView. The second view is added by Class Wizard, whose base class is CTreeView and the class name is CDirView. In function CMainFrame::OnCreateClient(...), the splitter window is created using the above two classes:

(Code omitted)

Functions CSplitterWnd::CreateStatic(...) and CSplitterWnd::CreateView(...) are called to create the splitter window and each individual pane. Please note that we must include "afxcview.h" in the header files of both class CExplorerView and CDirView, otherwise the compilation will generate errors.

The only result of this sample is a two-way splitted window. We will add further features in the next several sections.

4 Simple Explorer, Step 2: List Drives

Sample 4\Explorer is based on sample 3\Explorer.

We will display four types of items in the tree view window (left pane of splitter window): desktop, computer, drives, directories. The root node is desktop node, and there will be only one such type of node. Under the desktop node, there will be a computer node, which lists the computer name. Under the computer node, all the available drives will be listed, under each drive node, directories will be listed. With this structure, the file system of the whole computer can be displayed.

Creating Image List

Each node can have a label and also an associated image. Although they both are optional features, implementing them can make our application look more professional. To use images, we must create an image list and select it into the tree control. The image list can be created from either DIB images or icons. As we know from Chapter 5, the simplest way to create image list is to prepare images as the resources then load them at run time. In the sample, five images are prepared for the tree control, whose usage is listed in the following table:

(Table omitted)

Like all other types of views, the best place to initialize the tree is in function CDirView:: OnInitialUpdate(). In order to do so, we need to create the image list, select the image list into the tree control, and create the tree. Image list creation can be implemented by calling functions CImageList:: Create(...) and CImageList::Add(...). We can use the first function to create the image list, specify the image size and number of images that will be included in the list. Then we can call the second function to add each single image. In the sample, this procedure is implemented as follows:

(Code omitted)

Alternative Ways of Creating Image List

The image list is created using bitmap images. It can also be created from icons. Also, we can use one single image to create an image list that contains several images. In order to do so, we need to combine all the images together to form one image (align them horizontally, just as the image used for creating tool bar), and call one of the following versions of function CImageList::Create(...):

BOOL CImageList::Create(UINT nBitmapID, int cx, int nGrow, COLORREF crMask);

BOOL CImageList::Create(LPCTSTR lpszBitmapID, int cx, int nGrow, COLORREF crMask);

The image list can also be created from two existing image lists by calling the following version of this function:

(Code omitted)

We set the background color to white so that all image's portion with white color will be treated as transparent region.

Setting Styles of Tree Control

We can set the styles of the tree control by calling function ::SetWindowLong(...). This function is not the member function of class CTreeView, and can be called to change the styles of any window. In order to know which styles can be customized, we can look at the documentation of function CTreeCtrl:: Create(...). Generally, any style that can be set to parameter dwStyle of this function can also be used by function ::SetWindowLong(...) to change the style of a tree control. The following code fragment shows how the default styles of the tree control are customized in the sample (within function CDirView:: OnInitialUpdate()):

(Code omitted)

Style TVS_HASLINES will let the nodes be connected by dotted lines, TVS_LINESATROOT will add a line at the root node, and TVS_HASBUTTONS will add a rectangle button (displays either "+" or "-") for each expandable node. If we do not specify these styles, the tree control will look slightly different.

These styles can also be customized in function CView::PreCreateWindw(...). In order to do so, we need to set the corresponding style flags for member dwExStyle of structure CREATESTRUCT. The difference between two methods is that using ::SetWindowLong(...) can let us change the styles of a window dynamically.

Adding Root Node

The next step is to add nodes to the tree. We need to call function CTreeCtrl::InsertItem(...) to add a node to the tree. To call this function, we need to prepare a TV_INSERTSTRUCT type object, and specify the properties of node. For example, we can specify the node's parent, associated image, label and states. This procedure has been discussed in chapter 5. One thing we need to pay attention to is that since InsertItem(...) is not a member function of CTreeView, we must first call function CTreeView::GetTreeCtrl() to obtain the tree control before adding any node. The following portion of function CDirView::OnInitialUpdate() shows how the root node is added:

(Code omitted)

Finding out Available Drives in the System

By stuffing TV_INSERTSTRUCT type object and calling function CTreeCtrl::InsertItem(...) repeatedly, the tree can be created. However, before proceeding to create other nodes, we need to find out all the available drives in the system.

Currently there can be at most 26 drives contained in one system, which are labeled from "A:" to "Z:". We can call runtime function _chdrive(...) to change the current working drive (Calling this function has the same effect with typing command "a:" in a DOS prompt window). Function _chdrive(...) has one parameter:

int _chdrive(int drive);

Parameter drive specifies target drive. It can be any number from 1 to 26, which represents drive A:, B:, C:... and so on. The function will return 0 if the working drive is changed successfully, otherwise it returns -1.

So we can call this function repeatedly by passing 1, 2, 3...26 to it and examining the returned value. If the function returns 0, this means the drive is available, and we need to add it to the tree control. If the function returns -1, we can just go on to check the next drive.

Because we do not want to change the default working drive, we need to save the current working drive before calling function _chdrive(...), and resume it after the checking is over. The current working drive can be retrieved by calling runtime function _getdrive(). The following portion of function CDirView:: OnInitialUpdate() shows how the drives are added to the tree view window:

(Code omitted)

When program exits, we must do some cleanup job, which includes removing all the nodes and destroying the image list. In the sample, this is implemented in WM_DESTROY message handler:

(Code omitted)

5 Simple Explorer, Step 3: Listing Directories

Sample 5\Explorer is based on sample 4\Explorer.

In the previous section, we called function _chdrive(...) to find out all the available drives in the system. In order to add the directories (sub-directories) to the tree view window, we need to enumerate directories and files.

Enumerating Files and Directories

In MFC, class CFileFind can be used to enumerate files and directories under certain path. If we call this function for all the directories and sub-directories contained in the system, finally we will get all the information about the file system.

To enumerate files and directories contained in the current working directory, we can start from calling function CFileFind::FindFile(). Then we can call function CFileFind::FindNextFile() repeatedly until it returns a FALSE value. The following code fragment shows how to enumerate all the files and directories contained in the current working directory:

(Code omitted)

Note we can also use wildcard characters when calling function CFileFind::FindFile(...) to match file name with specific patterns. If we do not pass any parameter to it, it will be equal to passing "*.*" to the function. In this case all the files and directories will be enumerated. If function CFileFind:: FindNextFile() returns a non-zero value, we can call several other member functions of class CFileFind to obtain the properties of the enumerated file such as file name, file path, file attributes, created time and updated time.

Adding Directory Nodes

In order

Page : << Previous 3  Next >>