• Thứ Ba, 18/09/2007 10:55 (GMT+7)

    viết chương trình hiển thị cây thư mục (giống như lệnh dir của dos) bãng C++?

    Câu hỏi :
    Xin hướng dẫn viết chương trình hiển thị cây thư mục (giống như lệnh dir của dos) bãng C++.

    Trả lời :

    Nếu lập trình bằng VC++ trên Windows, bạn có thể dùng 2 class MFC sau đây để duyệt nội dung thư mục và hiển thị kết quả lên màn hình dễ dàng và tin cậy:

     - Class CFileFind cho phép duyệt thư mục theo cơ chế đệ quy để tìm mọi phần tử con của 1 thư mục xác định. Hai tác vụ thường dùng nhất là FindFile() và FindNextFile().
     - Class CTreeCtrl cho phép hiển thị các phần tử thư mục lên màn hình theo dạng cây phân cấp như bạn đã từng thấy trong chương trình Windows Explorer. Hai tác vụ thường dụng nhất là InsertItem() và Expand().

    Sau đây là qui trình điển hình để viết ứng dụng duyệt cây thư mục đơn giản bằng VC++:
     1. Chạy VC++, tạo Project quản lý ứng dụng với tên là DirTree, chọn loại giao diện ứng dụng là "Dialog Based" rồi thiết kế trực quan cửa sổ ứng dụng gồm 4 phần tử Label, Textbox, Button và TreeView như hình.

     2. Nhấn phải chuột trên đối tượng TreeView, chọn mục Properties để hiển thị cửa sổ thuộc tính của nó. Chọn tag "Styles" rồi đánh dầu chọn các checkbox "Has buttons", "Has Lines", "Lines at root".

     3. Chọn menu View.ClassWizard để hiển thị cửa sổ ClassWizard, chọn tên class nhận dạng cửa sổ giao diện vừa thiết kế (CDirTreeDlg).

     3.1 Chọn tab "Message Maps", chọn ID nhận dạng button Browse, chọn message BN_CLICKED, chọn button Add Function để định nghĩa hàm xử lý sự kiện click chuột trên button Browse, đặt tên hàm xử lý là OnBrowse (ta sẽ viết hàm này sau).

     3.2 Chọn button Add Class.New, khi cửa sổ "New class" hiển thị, bạn nhập vào tên class là CMyDirTree, chọn tên class cha (Base class) là CTreeCtrl trong danh sách rồi ấn button OK để tạo mới class CMyDirTree là con của phần tử TreeView vừa thiết kế trực quan.

     3.3 Chọn tab "Member Variables", chọn ID nhận dạng textbox, chọn button "Add Variable" để định nghĩa biến kết hợp với textbox, bạn đặt tên cho biến này là m_dirpath thuộc Category "Value" và kiểu CString.

     3.4 Chọn tab "Member Variables", chọn ID nhận dạng Treeview, chọn button "Add Variable" để định nghĩa biến kết hợp với TreeView, bạn đặt tên cho biến này là m_dirtree thuộc Category "Control" và kiểu CMyDirTree.

    Đoạn code C++ miêu tả class MyDirTree với chức năng hiển thị dạng cây phân cấp các thành phần của 1 thư mục xác định.

    3.5 Chọn lại tab "Message Maps", chọn hàm OnBrowse trong danh sách, nhấn button "Edit code" để mở cửa sổ soạn code cho hàm xử lý sự kiện này như sau:
     
     void CDirTreeDlg::OnBrowse() {
     // TODO: Add your control notification handler code here
     UpdateData (TRUE);
     m_dirtree.BrowseTree (m_pathdir);
     UpdateData (FALSE);
     }
     
     4. Chọn tab ClassView trong cửa sổ Project (thường ở phía trái màn hình) để hiển thị cây các class cấu thành ứng dụng, nhấn kép vào class CMyDirTree để hiển thị cửa sổ soạn code cho nó. Thường file MyDirTree.h sẽ được hiển thị, đây là file đặc tả class. Bạn hãy thêm 2 lệnh đặc tả 2 tác vụ sau vào nhóm public của class:
     void BrowseTree(CString dirpath);
     void ExploreDir(const CString strDir, HTREEITEM hParent);
     
     5. Nhấn chuột vào dấu + của mục CMyDirTree trong cây Project để hiển thị các tác vụ của class này, nhấn đúp chuột vào bất kỳ tác vụ nào của class để mở cửa sổ hiển thị file *.cpp miêu tả sự hiện thực chi tiết của class rồi viết 2 tác vụ BrowseTree() và ExploreDir() như sau:
     
     void CMyDirTree::BrowseTree(CString dirpath) {
     //xóa sạch các phần tử của cây hiện hành
     DeleteAllItems();
     //thiết lập record miêu tả nút gốc
     TV_INSERTSTRUCT tvstruct;
     tvstruct.hParent = NULL;
     tvstruct.hInsertAfter = TVI_LAST;
     tvstruct.item.pszText = dirpath.GetBuffer(200);
     tvstruct.item.mask = TVIF_TEXT;
     //thêm nút gốc vào cây
     HTREEITEM hThisItem = InsertItem(&tvstruct);
     //tạo cây thứ bậc từ thư mục dirpath
     ExploreDir(dirpath, hThisItem);
     //hiển thị các phần tử của thư mục dirpath
     Expand(hThisItem, TVE_EXPAND);
     }
     
     void CMyDirTree::ExploreDir(const CString strDir, HTREEITEM hParent) {
     TV_INSERTSTRUCT tvstruct;
     CString strSearchDir;
     CString strsubDir;
     //xây dựng pattern nhận dạng các phần tử của thư mục dirpath
     strSearchDir = strDir + "\\*";
     CFileFind localFind;
     //tìm phần tử đầu tiên
     BOOL bContinue = localFind.FindFile(strSearchDir);
     if (!bContinue) {
     //thư mục rỗng, không làm gì cả.
     localFind.Close();
     return;
     }
     HTREEITEM hThisItem;
     CString strFileName;
     //duyệt xử lý từng phần tử tìm được
     while (bContinue) {
     //lấy thông tin của phần tử hiện hành
     bContinue = localFind.FindNextFile();
     strFileName = localFind.GetFileName();
     //thiết lập record miêu tả nút miêu tả phần tử
     tvstruct.hParent = hParent;
     tvstruct.hInsertAfter = TVI_LAST;
     tvstruct.item.pszText = (LPTSTR)(LPCTSTR)strFileName;
     tvstruct.item.mask = TVIF_TEXT;
     if (strFileName != _T(".") && strFileName != _T("..")) {
     //thêm nút miêu tả phần tử vào cây
     hThisItem = InsertItem(&tvstruct);
     //nếu phần tử là thư mục con thì "ExploreDir" nó
     if (localFind.IsDirectory()) {
     strsubDir = strDir + "\\" + (LPTSTR)(LPCTSTR)strFileName;
     ExploreDir(strsubDir, hThisItem);
     }
     }
     }
     localFind.Close();
     return;
     }
     
     6. Chọn menu Build.Execute DirTree.exe để dịch và chạy thử ứng dụng. Nếu bạn thực hiện đúng qui trình trên và nhập đúng các lệnh C++ thì chương trình sẽ chạy tốt, bạn thử nhập vào textbox đường dẫn của thư mục nào đó rồi nhấn button Browse, bạn sẽ thấy cây thư mục sẽ hiển thị lên trong cửa sổ TreeView. Bạn có thể thao tác mở rộng/thu nhỏ nội dung của từng thư mục trong cây y như bạn đã làm trên Windows Explorer.

    Bạn có thể liên hệ với toà soạn TGVT để chép Project C++ DirTree do chúng tôi viết. Trong Project này, class MyDirTree là thiết yếu nhất.
     

    Chuyên mục: Lập trình