C++檔案(夾)選擇對話方塊操作
由於各種應用,我們需要呼叫系統的開啟檔案對話方塊或者開啟資料夾對話方塊,或兩者兼有。今遇到這個情況已經解決,特寫下這篇博文。
1.開啟檔案對話方塊常用的方法是使用系統的CFileDialog。這裡介紹另外一種方法就是使用OPENFILENAME這個結構體和GetOpenFileName()這個函式,可以實現單選檔案或者多選檔案,程式碼如下:
需引入標頭檔案#include "CommDlg.h"
TCHAR szBuffer[MAX_PATH] = {0}; OPENFILENAME ofn= {0}; ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = _T("Exe檔案(*.exe)\0*.exe\0所有檔案(*.*)\0*.*\0");//要選擇的檔案字尾 ofn.lpstrInitialDir = _T("D:\\Program Files");//預設的檔案路徑 ofn.lpstrFile = szBuffer;//存放檔案的緩衝區 ofn.nMaxFile = sizeof(szBuffer)/sizeof(*szBuffer); ofn.nFilterIndex = 0; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER ;//標誌如果是多選要加上OFN_ALLOWMULTISELECT BOOL bSel = GetOpenFileName(&ofn);
這樣就可以開啟選擇檔案對話方塊了。可以選擇需要的檔案。szBuffer是存放的選擇的檔案路徑。
多選
下面的程式碼演示瞭如何得到GetOpenFileName允許多選的情況下選擇的檔名#include <windows.h> int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) { OPENFILENAME ofn; TCHAR szOpenFileNames[80*MAX_PATH]; TCHAR szPath[MAX_PATH]; TCHAR szFileName[80*MAX_PATH]; TCHAR* p; int nLen = 0; ZeroMemory( &ofn, sizeof(ofn) ); ofn.Flags = OFN_EXPLORER | OFN_ALLOWMULTISELECT; ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = szOpenFileNames; ofn.nMaxFile = sizeof(szOpenFileNames); ofn.lpstrFile[0] = '/0'; ofn.lpstrFilter = TEXT("All Files(*.*)/0*.*/0"); if( GetOpenFileName( &ofn ) ) { //把第一個檔名前的複製到szPath,即: //如果只選了一個檔案,就複製到最後一個'/' //如果選了多個檔案,就複製到第一個NULL字元 lstrcpyn(szPath, szOpenFileNames, ofn.nFileOffset ); //當只選了一個檔案時,下面這個NULL字元是必需的. //這裡不區別對待選了一個和多個檔案的情況 szPath[ ofn.nFileOffset ] = '/0'; nLen = lstrlen(szPath); if( szPath[nLen-1] != '//' ) //如果選了多個檔案,則必須加上'//' { lstrcat(szPath, TEXT("//")); } p = szOpenFileNames + ofn.nFileOffset; //把指標移到第一個檔案 ZeroMemory(szFileName, sizeof(szFileName)); while( *p ) { lstrcat(szFileName, szPath); //給檔名加上路徑 lstrcat(szFileName, p); //加上檔名 lstrcat(szFileName, TEXT("/n")); //換行 p += lstrlen(p) +1; //移至下一個檔案 } MessageBox(NULL, szFileName, TEXT("MultiSelect"), MB_OK); } }
開啟資料夾對話方塊方法:
需引入標頭檔案:#include "Shlobj.h"
TCHAR szBuffer[MAX_PATH] = {0}; BROWSEINFO bi; ZeroMemory(&bi,sizeof(BROWSEINFO)); bi.hwndOwner = NULL; bi.pszDisplayName = szBuffer; bi.lpszTitle = _T("從下面選資料夾目錄:"); bi.ulFlags = BIF_RETURNFSANCESTORS; LPITEMIDLIST idl = SHBrowseForFolder(&bi); if (NULL == idl) { return; } SHGetPathFromIDList(idl,szBuffer);
上面的程式碼就可以開啟一個選擇資料夾對話方塊了。
選擇檔案或資料夾對話方塊的呼叫:
TCHAR szBuffer[MAX_PATH] = {0}; BROWSEINFO bi; ZeroMemory(&bi,sizeof(BROWSEINFO)); bi.hwndOwner = NULL; bi.pszDisplayName = szBuffer; bi.lpszTitle = _T("從下面選擇檔案或資料夾:"); bi.ulFlags = BIF_BROWSEINCLUDEFILES; LPITEMIDLIST idl = SHBrowseForFolder(&bi); if (NULL == idl) { return; } SHGetPathFromIDList(idl,szBuffer);
使用了上面的程式碼就可以根據需要選擇檔案或者檔案夾了。
建立一個可以新建資料夾且指定選中初始路徑的瀏覽資料夾對話方塊
由於我在實際工作中需要的就是一個有新建資料夾功能且指定初始選中路徑的瀏覽資料夾對話方塊,就把這個需求當做擴充套件應用吧,由於對話方塊樣式由ulFlags標記確定,而在系統標頭檔案SHLOBJ.h標頭檔案中給出的對話方塊樣式只有如下幾種
// Browsing for directory. #define BIF_RETURNONLYFSDIRS 0x0001 // For finding a folder to start document searching #define BIF_DONTGOBELOWDOMAIN 0x0002 // For starting the Find Computer #define BIF_STATUSTEXT 0x0004 #define BIF_RETURNFSANCESTORS 0x0008 #define BIF_EDITBOX 0x0010 #define BIF_VALIDATE 0x0020 // insist on valid result (or CANCEL) #define BIF_BROWSEFORCOMPUTER 0x1000 // Browsing for Computers. #define BIF_BROWSEFORPRINTER 0x2000 // Browsing for Printers #define BIF_BROWSEINCLUDEFILES 0x4000 // Browsing for Everything
沒有滿足我需求的樣式,通過csdn查到其實有一個支援新建資料夾功能的樣式值0x40,通常網路上給出巨集為BIF_NEWDIALOGSTYLE和BIF_USENEWUI,由於不知道在具體哪個標頭檔案中,所以我們可以在程式碼中自己定義一下這兩個巨集,具體如下
#define BIF_NEWDIALOGSTYLE 0x40 #define BIF_USENEWUI (BIF_NEWDIALOGSTYLE|BIF_EDITBOX)
這樣一來第一個問題解決了,那麼如何讓對話方塊有初始選中的資料夾路徑呢,我起初想著通過pidlRoot,結果撞了一鼻子灰,原來設定初始選中資料夾路徑,是通過那個神奇的回撥函式來實現,換句話來說你呼叫SHBrowseForFolder也就好比你呼叫了CDialog::DoModal()函式,具體這個對話方塊裡面的類似初始化,選擇等操作的不同實現就通過lpfn這個回撥函式來實現了。
下面給出這個簡單擴充套件的程式碼
#define BIF_NEWDIALOGSTYLE 0x40 int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData) { if(uMsg == BFFM_INITIALIZED) { SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); } return 0; } void CSisAppendMidDlg::OnButtonSisdes() { // TODO: Add your control notification handler code here BROWSEINFO bi; char Buffer[MAX_PATH]; //初始化入口引數bi開始 bi.hwndOwner = NULL; bi.pidlRoot =NULL;//初始化制定的root目錄很不容易 bi.pszDisplayName = Buffer;//此引數如為NULL則不能顯示對話方塊 bi.lpszTitle = "選擇Sis目標檔案路徑"; bi.ulFlags = BIF_EDITBOX|BIF_NEWDIALOGSTYLE; CFileFind finder; if(finder.FindFile(m_cSisDes)==FALSE) { bi.lParam =0; bi.lpfn = NULL; } else { bi.lParam = (long)(m_cSisDes.GetBuffer(m_cSisDes.GetLength()));//初始化路徑,形如(_T("c:\\Symbian")); bi.lpfn = BrowseCallbackProc; } finder.Close(); bi.iImage=IDR_MAINFRAME; //初始化入口引數bi結束 LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//呼叫顯示選擇對話方塊 if(pIDList) { SHGetPathFromIDList(pIDList, Buffer); //取得資料夾路徑到Buffer裡 m_cSisDes = Buffer;//將路徑儲存在一個CString物件裡 } UpdateData(FALSE); // free memory used IMalloc * imalloc = 0; if ( SUCCEEDED(SHGetMalloc( &imalloc))) { imalloc->Free (pIDList); imalloc->Release(); } }
下一步實用記錄iostream對檔案的讀寫操作
特此記錄
Copyright @WinkJie