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


new item to the list control. Here is how it is implemented in function CExplorerView::ChangeDir():

(Code omitted)

Unlike tree control, there is no handle here to identify a special item. All the items are identified by their indices, this means if we display items in "list" or "report" style, the item located at the first row is item 0, the next row is item 1... and so on. When inserting an item, we need to specify the item index by using member iItem of LV_ITEM structure.

We store file size (for directory, display nothing), file type ("File" or "Folder"), the updated time in a string array that will be used to add text for the sub-items. These attributes of file can be retrieved by calling functions CFileFind::GetLength(), CFileFind::IsDirectory() and CFileFind:: GetLastWriteTime(...). When calling the third function to obtain the update time of a file, we get a CTime type variable. To store the time in a CString type variable in ASCII format, we need to call function CTime::Format(...). The following portion of function CExplorerView::ChangeDir() shows how the string array is created:

(Code omitted)

The text of sub-items is added by calling function CListCtrl::SetItemText(...). This can also be implemented by stuffing LV_ITEM type object (specifying item and sub-item indices) and calling function CListCtrl::SetItem(...). The following portion of function CExplorerView::ChangeDir() shows how this is implemented in the sample:

(Code omitted)

Destroying the Old List

Whenever the current working directory is changed, we need to call function CExplorerView:: ChangeDir() to create new file list. Before building a new one, we need to delete the old list. In the sample, this is implemented by function CExplorerView::DestroyList(). Within this function, both list items and image lists are deleted:

(Code omitted)

Since we can retrieve the pointers of image list from the list control, there is no need for us to store them as variables. This function is called in function CExplorerView::ChangeDir() and WM_DESTROY message handler.

Using Function CExplorerView::ChangeDir()

At this point, we still do not allow the user to select a directory by clicking on a directory node in the tree view window. So we can only display the files and directories contained in the root directory when the application is first invoked. This is implemented in function CExplorerView::OnInitialUpdate(), where we find the first available drive, and call function CExplorerView::ChangeDir() to create the list view:

(Code omitted)

7 Simple Explorer, Step 5: Displaying Registered Icons

Windows( encourages all types of files to register specific icons to the system, so that when they are displayed in certain applications such as "Explorer", the registered icons (also called Shell Icon) can be used to distinguish between different type of files. However, some file types do not have registered icons and some files contain icons within themselves (such as files with ".exe" or ".dll" extension).

Which Icon to Use

Windows( always try to display a file using the appropriate icons. If a file contains icon itself, this icon will be used. If a file doesn't contain any icon but has registered icons (such as some special document files like "*.bmp", "*.doc"), the registered icons will be used. If no registered icons are found, a default icon will be assigned to the file.

There is a shell function that can be used to retrieve the icon information for a file:

WINSHELLAPI DWORD WINAPI SHGetFileInfo

(

LPCTSTR pszPath, DWORD dwFileAttributes, SHFILEINFO FAR *psfi,

UINT cbFileInfo, UINT uFlags

);


Here parameter pszPath is a pointer to a string specifying the file path; dwFileAttributes specifies the file attributes, and the file information can be retrieved into a SHFILEINFO type object which is pointed by pointer psfi; cbFileInfo specifies the size of SHFILEINFO structure; uFlags specifies what information is being retrieved. In our case, we can combine SHGFI_ICON with one of the following flags and pass the result to parameter uFlags:

(Table omitted)

To display each file with embedded or registered icons, before adding an item to the list control, we need to first customize the image list. If any icon is found by calling function ::SHGetFileInfo(), we will add it to the image list. If we could not find an icon using this method, the default icon will be associated with the corresponding file.

Sample

Sample 7\Explorer is based on sample 6\Explorer. In this sample, the embedded and registered icons are retrieved for displaying files in the list view.

In the sample, a new member function is added for retrieving icons for a file:

HICON CExplorerView::GetIconFromFile(CString szFileName, UINT uFlags);

The returned value is an icon handle. Within this function, ::SHGetFileInfo(...) is called to get the icon information of a file. The following is the implementation of this function:

(Code omitted)

Function CExplorerView::ChangeDir() is modified as follows: after a file is found, function CExplorerView::GetIconFromFile(...) is called to find its embedded or registered icons; if this is successful, the newly obtained icons will be added to the image list and associated with the file; otherwise the default images will be used. The following portion of function CExplorerView::ChangeDir() shows how we try to find the embedded icons of a file:

(Code omitted)

In rare cases, some files may have small embedded or registered icon but no corresponding big icon, or vice versa. In any case, the embedded or registered icon has the highre priority to be used. The newly obtained icon is added to the image list by calling function CImageList::Add(...).

8 Simple Explorer, Step 6: Clicking and Double Clicking

Sample 8\Exoplorer is based on sample 7\Explorer. In this sample, when the user clicks or double clicks the left button on a directory node contained in the tree control, the current working directory will be changed and the contents of the list view will also be updated.

If the double clicking expands a node, we need to pay attention to the newly revealed nodes: if any directory contains sub-directories, we need to add new nodes so that the node button will be automatically enabled.

Tree Control Messages

Mouse clicking events are sent through WM_NOTIFY messages. For tree control, various activities of tree items can be handled by processing this message. In MFC, this message can be mapped to a member function by using macro ON_NOTIFY_REFLECT. This macro has two parameters, the first specifies the event type, the second specifies the member function name. There are many types of events, for example, mouse button clicking event is defined as NM_CLICK, and the node expanding event is defined as TVN_ITEMEXPANDING. Fortunately, in MFC, message mapping for these events can be easily implemented through using Class Wizard. In sample 8\Explorer, we trap mouse clicking and node expanding events to functions CDirView:: OnClick(...) and CDirView::OnItemExpanding(...) respectively.

Obtaining Full Path

When the user clicks mouse on a node, first we need to find out the path represented by that node. Although the directory name is stored as the item text for each node, it is not a full path. We need a full path in order to change the current working directory. In the sample, function CDirView::GetDir(...) is implemented to obtain the full path represented by any item. Within this function, we keep on retrieving the item's parent node until root is reached, and combining the obtained directory names to form a full path.

Finding out the Clicked Item

After receiving NM_CLICK notification, we can call function CTreeCtrl::HitTest(...) to find out the handle of the item that was clicked. We need to pass the current mouse position to this function. The returned value should be the handle of the item that is currently under the mouse cursor. If the mouse is not over any item, the function will return NULL. Please note that when calling this function, the coordinates of the mouse cursor should be in the coordinate system of the client window. We need to call function CWnd::ScreenToClient(...) to make the conversion.

When an Item Is Clicked

Special attention needs to be paid to directory nodes labeled with "." and "..". When they are clicked, the current working directory should be changed differently. For the purpose of demonstration, in the sample, no change will be made if the user clicks any of the two types of directories. If the user clicks a normal directory node, we need to change the current working directory to the selected one and notify the list view to update its contents. This notification is made through calling function CBrowserDoc::ChangePath(), within which function CBrowserView::ChangeDir() is called. However, if the user clicks on the currently selected directory, no change will be made. The following is the message handler for mouse left button clicking:

(Code omitted)

When a Node Expands

When a node is expanding, we need to check the newly revealed nodes to see if they always contain child nodes. If not, we need to add child nodes (if they have sub-directories) to them because this will enable node button automatically. In the sample, function CDirView::AddChildrenChildren() is implemented to let us add new nodes for all the child nodes of a given node. Within this function, we check each child node to see if it already has child items (which means the sub-directories have already been added for this node). If not, we call function CDirView::AddDirs(...) to add new nodes to it. A node's child item can be enumerated by calling function

Page : << Previous 5  Next >>