線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:6279
推到 Plurk!
推到 Facebook!

如何在選擇目錄時也能新增目錄呢 ?

尚未結案
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-06-08 13:38:39 IP:61.222.xxx.xxx 未訂閱
請教各位 : 我現在是用 SelectDirectory("選擇目錄", "", Dir) 來開啟一個對話框, 讓使用者選擇目錄。 可是現在的問題是,使用者只能選擇目錄,卻無法新建目錄, 可是我們有些軟體裡頭,在選擇目錄的對話框裡,又有另一個按鈕可以讓使用者新建目錄。 我想請問,這要怎麼辦到呢 ? -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
shychef
一般會員


發表:5
回覆:10
積分:3
註冊:2004-10-02

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-06-08 15:43:44 IP:211.23.xxx.xxx 未訂閱
AnsiString Dir = "C:\\Program Files"; if (SelectDirectory(Dir, TSelectDirOpts() << sdAllowCreate << sdPerformCreate << sdPrompt,SELDIRHELP)) Label1->Caption = Dir; 執行後,在 Directory Name: C:\Program Files在這後面加 \myDirectory 就會跳出對話方塊,問你是不是要新增myDirectory這個目錄
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-06-08 16:50:56 IP:219.136.xxx.xxx 未訂閱
chtai 您好:    由 Help 對 SelectDirectory() 的說明可以知道,它有兩種方式可以呼叫,您使用的是第一種方式,但是第一種方式沒有提供 Options 的設定,而第二種方式則有提供一些設定選項,建立新目錄的選項就是其中之一,Help 的範例也有做該選項的設定,而這兩種呼叫方式的參數設定是不一樣的,如下: extern PACKAGE bool __fastcall SelectDirectory( const AnsiString Caption, const WideString Root, AnsiString &Directory); extern PACKAGE bool __fastcall SelectDirectory( AnsiString &Directory, TSelectDirOpts Options, int HelpCtx); 而這兩種方式所呼叫出來的選擇視窗,其型態也是不一樣的,如果您能接受第二種呼叫方式所產生的視窗,也就是 Help 範例所產生的對話框樣式:
#include     const SELDIRHELP = 1000;    void __fastcall TForm1::Button1Click(TObject *Sender)
{
  AnsiString Dir = "C:\\Program Files\\MyApp";
  if (SelectDirectory(Dir, TSelectDirOpts() << sdAllowCreate << sdPerformCreate << sdPrompt, SELDIRHELP))
    Label1->Caption = Dir;
}
那就 OK 了。 但是如果您想使用您現在所呼叫的那種對話框,而且也仍想要有建立新目錄的功能的話,那麼就可能要改用其它方式來處理了,我的印象中好像是與 SHBrowseForFolder() 有關,但我並不是很確定,您若是實際上需要的是這種樣式的對話框,那我就得再查查看了。
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-06-08 17:12:08 IP:203.70.xxx.xxx 未訂閱
引言: AnsiString Dir = "C:\\Program Files"; if (SelectDirectory(Dir, TSelectDirOpts() << sdAllowCreate << sdPerformCreate << sdPrompt,SELDIRHELP)) Label1->Caption = Dir; 執行後,在 Directory Name: C:\Program Files在這後面加 \myDirectory 就會跳出對話方塊,問你是不是要新增myDirectory這個目錄
謝謝回應, 這個我也有試過,可是它的介面太醜了, 我不喜歡。 -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-06-08 17:33:39 IP:219.136.xxx.xxx 未訂閱
chtai 您好:    以下的截圖是我使用 SHBrowseForFolder() 來建立的對話框,但是您仍未告知您要的是不是這樣的對話框?
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-06-08 17:36:49 IP:203.70.xxx.xxx 未訂閱
引言: 但是如果您想使用您現在所呼叫的那種對話框,而且也仍想要有建立新目錄的功能的話,那麼就可能要改用其它方式來處理了,我的印象中好像是與 SHBrowseForFolder() 有關,但我並不是很確定,您若是實際上需要的是這種樣式的對話框,那我就得再查查看了。
感謝您的回應,我也有在 help 看到它的範例了, 只可惜第二種的介面太醜了, 所以客戶要求,要用第一種的介面,然後又可以建立新目錄 還望
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-06-08 17:46:37 IP:219.136.xxx.xxx 未訂閱
我現在有事要去處理,如果您對我前一個問題的回覆是肯定的,那麼等我回來後,再整理一下資料貼上來。
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-06-08 18:04:39 IP:203.70.xxx.xxx 未訂閱
引言: chtai 您好: 以下的截圖是我使用 SHBrowseForFolder() 來建立的對話框,但是您仍未告知您要的是不是這樣的對話框?
是的,就是這樣 還請
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-06-08 22:50:16 IP:219.136.xxx.xxx 未訂閱
chtai 您好:    以下就是我整理好的程式碼,我將 SHBrowseForFolder() 寫成一個自定函式,命名為 SetDirectory(),共使用三個參數,我僅加註了部份說明,整個函式的重點在 BROWSEINFO 及 SHBrowseForFolder(),相關用途與設定方式可參考 Help 上的說明,以便視個人的需要去做調整:
#include 
#include   // 為了使用 GlobalFreePtr()    // 如果 shlobj.h 內未定義 BIF_NEWDIALOGSTYLE,請自定如下:
#define BIF_NEWDIALOGSTYLE  0x0040    /*
SetDirectory 自定函式:    功能簡述:
    1. 顯示選擇目錄對話框,並提供 "新資料夾" 的按鈕項目,可在選擇目錄對話框直接建立新目錄。
    2. 可取得被選擇目錄的路徑字串,以及被選擇目錄的名稱字串 (如果有的話)    bool SetDirectory(AnsiString StartDir, AnsiString *selDir, AnsiString *dirName)    參數說明:
    StartDir: 開啟對話框時的起始目錄。
    selDir:   選擇目錄後存放目錄路徑的字串,例如:C:\
    dirName:  選擇目錄後存放目錄名稱的字串,例如:本機磁碟 (C:)    傳回值:  取消傳回 false,選擇目錄則傳回 true
*/    bool __fastcall SetDirectory(AnsiString StartDir, AnsiString *selDir, AnsiString *dirName)
{
    auto bool rc = true;        BROWSEINFO bi;
    char PathStr[MAX_PATH];
    char FolderName[MAX_PATH];
    LPITEMIDLIST ItemID;
    memset(&bi, 0, sizeof(BROWSEINFO));
    memset(PathStr, 0, MAX_PATH);
    bi.hwndOwner      = Application->Handle;
    bi.pszDisplayName = FolderName;
    bi.lpszTitle      = "選擇資料夾";
    bi.ulFlags        = BIF_RETURNONLYFSDIRS | BIF_DONTGOBELOWDOMAIN | BIF_NEWDIALOGSTYLE;
    bi.lpfn           = reinterpret_cast (BrowseCallbackProc);
    bi.lParam         = reinterpret_cast  (StartDir.c_str());        CoInitialize(NULL);
    ItemID = SHBrowseForFolder(&bi);
    if(ItemID == NULL){
        rc = false;
    }else{
        SHGetPathFromIDList(ItemID, PathStr);
    }
    GlobalFreePtr(ItemID);
    CoUninitialize();        *selDir = PathStr;
    *dirName = FolderName;        return rc;
}    // 使用範例
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    AnsiString StartDirectory = "C:\\";  // 設定對話框起始目錄
    AnsiString SelectedDirectory;  // 儲存被選擇目錄的路徑字串
    AnsiString DirectoryName;  // 儲存被選擇目錄的名稱字串
    if(SetDirectory(StartDirectory, &SelectedDirectory, &DirectoryName)){
        ShowMessage("選擇目錄:" SelectedDirectory "\n目錄名稱:" DirectoryName);
    }
}
andychang1690
資深會員


發表:20
回覆:694
積分:442
註冊:2003-03-14

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-06-08 23:49:22 IP:221.169.xxx.xxx 未訂閱
幫RedSnow大大補充:
bi.ulFlags        =
  // 新式樣(BIF_NEWDIALOGSTYLE)創建一個更大的,可變大小的對話方塊,對應的按鈕是"Make New Folder"--
  // 如果你指定 BIF_EDITBOX--則有一個編輯框,用戶可以敲入文件夾的名字。
  // 其他標誌還有 BIF_BROWSEFORCOMPUTER,用於顯示電腦,
  // BIF_BROWSEFORPRINTER 用於印表機。
  // BIF_RETURNONLYFSDIRS 告訴 Windows 僅返回文件系統目錄,而非偽文件夾,如網路鄰居,
  // BIF_STATUSTEXT 創建一個狀態視窗,你可以設置其文本。
  // (新式對話方塊不支援 BIF_STATUSTEXT)。
  // 完整的標誌清單請參考 BROWSEINFO 文檔。--->>>VC,不是BCB Windows SDK
請參考!    
Andy Chang 發表人 - andychang1690 於 2005/06/08 23:50:17
------
Andy Chang
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-06-09 09:48:46 IP:203.70.xxx.xxx 未訂閱
引言: bi.lpfn = reinterpret_cast (BrowseCallbackProc); bi.lParam = reinterpret_cast (StartDir.c_str());
繼續請教,這兩句是什麼意思呢 ? 我看了看 MSDN, 不是只要設定 bi 裡的 pidlRoot 就可以指定起始目錄了嗎 ? -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
andychang1690
資深會員


發表:20
回覆:694
積分:442
註冊:2003-03-14

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-06-09 13:41:46 IP:221.169.xxx.xxx 未訂閱
[Code]chtai: Windows API函數SHBrowseForFolder, 完整聲明為WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(LPBROWSEINFO lpbi),返回一個ITEMIDLIST類型的指標, 通過這個指標調用函數SHGetPathFromIDList可以確定所選擇的目錄的全名稱。入參為BROWSEINFO結構的指標,這個結構較為複雜, 成員如下所示: HWND hwndOwner; // 擁有對話方塊的窗口,可以設置為Application->Handle LPCITEMIDLIST pidlRoot; // ITEMIDLIST類型的指標,表示在哪個路徑下選擇,一般可以設置為NULL LPSTR pszDisplayName; // 選擇後,所選目錄的名稱(不包含父級目錄)被拷貝到這個指標指向的位置 LPCSTR lpszTitle; // 作為標題顯示在對話方塊中目錄樹的上面,可以根據實際情況設置 UINT ulFlags; // 標誌位元,有點複雜,一般設置為BIF_RETURNONLYFSDIRS BFFCALLBACK lpfn; // 回調函數,一般不用,設置為NULL LPARAM lParam; // 預定義的對話方塊傳遞給回調函數的值 int iImage; // 與所選目錄相關聯的圖示在系統圖示集合中的索引 可以看出,使用函數SHBrowseForFolder還真麻煩 請參考! Andy Chang
------
Andy Chang
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-06-09 14:48:00 IP:61.222.xxx.xxx 未訂閱
多謝回應 :) 那再請教的是,若我想指定初始的選擇目錄 (例如 D:\MyApp ), 又不想用 RedSnow 大哥程式裡的那兩行 (因為我還不是很懂:p) (我明明有 include shlobj.h 了, 它卻說 undefined symbal BrowseCallbackProc ) 那要怎麼辦到才好呢 ? -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁 發表人 - chtai 於 2005/06/09 18:04:07
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-06-09 20:48:58 IP:219.135.xxx.xxx 未訂閱
chtai 您好:    真是抱歉,我剪貼資料貼上來時漏了一段,今天又出門一整天,因此剛剛才看到,補上 BrowseCallbackProc() 程序如下:
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lpData){
    if(uMsg == BFFM_INITIALIZED){
        PCSTR prevDir = reinterpret_cast  (lpData);
        if(DirectoryExists(prevDir)) SendMessage(hwnd, BFFM_SETSELECTION, static_cast  (1L), lpData);
    }
    return 0;
}
這一段放在 SetDirectory() 自定函式之前即可 (前一篇也補上去了,以免其他人參考時也漏掉)。 這個 CallBack 程序是必要的,否則對話框起始時會無法指向 StartDir 設定的目錄,您可以試著將 bi.lpfn 參數設為 NULL,然後比較一下有何差異就知道了。 發表人 - RedSnow 於 2005/06/09 22:28:08
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#15 引用回覆 回覆 發表時間:2005-06-10 01:40:57 IP:59.104.xxx.xxx 未訂閱
引言:
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lpData){
    if(uMsg == BFFM_INITIALIZED){
        PCSTR prevDir = reinterpret_cast  (lpData);
        if(DirectoryExists(prevDir)) SendMessage(hwnd, BFFM_SETSELECTION, static_cast  (1L), lpData);
    }
    return 0;
}
請問最後一行的 static_cast (1L) 裡的 1L 是哪來的阿? 完全沒看到這個變數阿~ 還有像是 MAX_PATH 也是,都是在哪定義的阿 < > 為什麼各位強者都知道這些東西怎麼用阿 < > 另外,有辦法讓 StartDir 展開嗎? -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
andychang1690
資深會員


發表:20
回覆:694
積分:442
註冊:2003-03-14

發送簡訊給我
#16 引用回覆 回覆 發表時間:2005-06-10 02:39:45 IP:221.169.xxx.xxx 未訂閱
chtai:我微修改RedSnow的程式相信比較簡單一些!
TForm1 *Form1;
AnsiString StartDirectory ; // 設定對話框起始目錄;變成全域變數    int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lpData)
{
  if(uMsg == BFFM_INITIALIZED)
    return SendMessage(hwnd, BFFM_SETSELECTION, true, (LPARAM)(LPCTSTR)(StartDirectory.c_str()));
  else
    return 1;
}
// 使用範例
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    StartDirectory = "C:\\";  // 設定對話框起始目錄
    AnsiString SelectedDirectory;  // 儲存被選擇目錄的路徑字串
    AnsiString DirectoryName;  // 儲存被選擇目錄的名稱字串
    if(SetDirectory(StartDirectory, &SelectedDirectory, &DirectoryName)){
        ShowMessage("選擇目錄:" SelectedDirectory "\n目錄名稱:" DirectoryName);
    }
}    crstypes.inc
Const MAX_PATH  = 260  ' Max Directory Path Length    還有要注意
GlobalFree(ItemID); // 返回的ItemID佔用了系統資源,不要忘了釋放
資源一定要釋放!     請參考!
Andy Chang
------
Andy Chang
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#17 引用回覆 回覆 發表時間:2005-06-10 10:46:25 IP:218.19.xxx.xxx 未訂閱
chtai 您好:
引言:請問最後一行的 static_cast (1L) 裡的 1L 是哪來的阿? 完全沒看到這個變數阿~
不知道您為何會認為 1L 會是一個變數?1L 是一個採用 "後綴表示規則" 的常數,而不是什麼變數,L 是 long-suffix (長整數字尾) 的意思,1L 是代表 "長整數 1"。
引言:還有像是 MAX_PATH 也是,都是在哪定義的阿
MAX_PATH 在 windef.h 裡有定義,SHBrowseForFolder() 引用 shlobj.h,而 shlobj.h 引用了其它的 .h 檔案,在一連串的引用過程中,只要其中有一檔案引用到了 windef.h 檔,MAX_PATH 就不會是未宣告的狀態。
引言:為什麼各位強者都知道這些東西怎麼用阿
查閱文件 參考範例 搜尋資料 詢問 練習 .... 經驗累積 = 知道如何使用。
引言:另外,有辦法讓 StartDir 展開嗎?
不知道您想要展開 StartDir 的什麼?請再描述得具體一點。 發表人 - RedSnow 於 2005/06/10 11:02:30
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#18 引用回覆 回覆 發表時間:2005-06-12 02:30:55 IP:59.104.xxx.xxx 未訂閱
引言:
引言:請問最後一行的 static_cast (1L) 裡的 1L 是哪來的阿? 完全沒看到這個變數阿~
不知道您為何會認為 1L 會是一個變數?1L 是一個採用 "後綴表示規則" 的常數,而不是什麼變數,L 是 long-suffix (長整數字尾) 的意思,1L 是代表 "長整數 1"。
哎呀~~對耶, 我怎麼把這基本的東西都給忘了 ... 糗了 <>< face="Verdana, Arial, Helvetica">引言:另外,有辦法讓 StartDir 展開嗎?不知道您想要展開 StartDir 的什麼?請再描述得具體一點。 [/quote] 就是假設我指定 StartDir 為 "D:\" 好了, 那它就會把 D:\ 這個 node 給 expand, 讓我可以看到底下有哪些目錄, 而不用自己再去點一下 D:\ 才會展開。 -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#19 引用回覆 回覆 發表時間:2005-06-12 22:34:18 IP:218.19.xxx.xxx 未訂閱
chtai 您好:    原本查看 MSDN 的 BrowseCallbackProc 文件時,看到一個訊息類型是 BFFM_SETEXPANDED,按照文件的說明來看,應該是可以使用和 BFFM_SETSELECTION 相同的參數,然後交由 SendMessage() 來設定截點的展開動作,但我就是試不出來,不知是否與 Shell DLL 的版本有關?
#define BFFM_SETEXPANDED     (WM_USER   106)
SendMessage(hwnd, BFFM_SETEXPANDED, static_cast  (1L), lpData);
因此我改用其它方式,先設法取得對話框上 TreeView 的 Handle 值,然後再取得被圈選的節點,最後再展開節點,以下是我加上節點展開處理後的 BrowseCallbackProc:
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lpData){
    if(uMsg == BFFM_INITIALIZED){
        PCSTR prevDir = reinterpret_cast  (lpData);
        if(DirectoryExists(prevDir)){
            SendMessage(hwnd, BFFM_SETSELECTION, static_cast  (1L), lpData);

            HWND shellCtrl = GetDlgItem(hwnd, 0);
            if(shellCtrl != NULL){
                HWND treeCtrl = GetDlgItem(shellCtrl, 0x64);
                TVITEMEX tvi;
                if(tvi.hItem = TreeView_GetSelection(treeCtrl)){
                    TreeView_GetItem(hwnd, &tvi);
                    TreeView_Expand(treeCtrl, tvi.hItem, TVE_EXPAND);
                }
            }
        }
    }
    return 0;
}
以上程序在我的環境可以正常運作,但是因為兩個 GetDlgItem() 函式的物件代碼 (0 與 0x64) 都是以 SPY 取得的,不知其是否具備固定性?因此請您自行測試一下 (包含 BFFM_SETEXPANDED 的 SendMessage 也可以試試看),看是否能達到您的需求?
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#20 引用回覆 回覆 發表時間:2005-06-14 11:18:06 IP:59.104.xxx.xxx 未訂閱
引言: 以上程序在我的環境可以正常運作,但是因為兩個 GetDlgItem() 函式的物件代碼 (0 與 0x64) 都是以 SPY 取得的,不知其是否具備固定性?因此請您自行測試一下 (包含 BFFM_SETEXPANDED 的 SendMessage 也可以試試看),看是否能達到您的需求?
報告: 物件代碼 (0 與 0x64) 在我的電腦 (WinXP SP2 BCB6) 可以正常執行。 可是 BFFM_SETEXPANDED 無效,真是奇也怪哉~ 若有其他前輩知道原因,還望不吝指點一二 --
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
licheer
一般會員


發表:23
回覆:20
積分:8
註冊:2007-08-19

發送簡訊給我
#21 引用回覆 回覆 發表時間:2007-09-21 01:26:41 IP:61.225.xxx.xxx 訂閱
我在BCB6中
照上面的說明使用
compiler 會錯誤
請問哪裡要修改呢?
謝謝


把出錯的那幾行刪掉
解決了~
編輯記錄
licheer 重新編輯於 2007-09-21 19:10:45, 註解 無‧
系統時間:2024-04-20 4:08:09
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!