Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / MFC

CBrowseCtrl - Adding File/Folder-Browse Features to Your Projects Easily

Rate me:
Please Sign up or sign in to vote.
4.93/5 (59 votes)
25 May 20045 min read 286.3K   7.8K   150   40
A file/folder browsing control that integrates an editbox and a button with built-in images

Sample Image - CBrowseCtrl.gif

Introduction

Usually, when we need to add file/folder-browse features to our projects, we have to do quite some trivia: first we must create a CEdit which will display the path name, then we need to create a CButton and handle its ON_BN_CLICKED event to launch the CFileDialog and copy the path name to the CEdit. Furthermore, if we want to make it look nice, we will have to include some icon or bitmap resources to decorate the CButton. It could cause some headache if we have multiple dialogs which all need the file/folder-browse feature on them.

I have been thinking that it would be nice if there was such a control in MFC, which integrates a CEdit and a CButton on it, handles the control events, pops up the CFileDialog and updates CEdit text automatically. And it'd be even nicer if that control has some built-in images, that is, it has its own drawing capability without requiring us to provide any image resource to it. And of course, some tooltips wouldn't hurt... Unfortunately, there's no such control in MFC, but fortunately, we can always make our own.

CBrowseCtrl is made for meeting the exact needs I described in the above paragraphs. It derives from CButton, has an editbox, a browse button and a tooltip on it. It can draw some built-in images on the browse button as well, so you don't need to include any icon or bitmap resources for this control. It handles button events by itself so whenever the user clicks on the browse button, a file/folder dialog pops up.

How to Use

You need to add source files BrowseCtrl.h and BrowseCtrl.cpp to your workspace first, and include BrowseCtrl.h wherever needed. To create the control, you can either use CBrowseCtrl::Create to create one at runtime, or draw a CButton on the dialog template and bind it with a CBrowseCtrl variable.

Code Samples

Specifying Control Styles

You may access the control styles anytime to change its appearance and behavior. Multiple style flags may be combined using the "|" operator. The valid style flags are:

Flag Effects
BC_CTL_ALLOWEDIT Allows user to type in the editbox
BC_CTL_FOLDERSONLY Browse for folders instead of files
BC_BTN_LEFT Display the browse button on the left-side of the editbox
BC_BTN_FLAT Use flat button style
BC_BTN_ICON Use icon, no text will be displayed
BC_ICO_ARROWFOLDER The arrow-folder icon, must be combined with BC_BTN_ICON
BC_ICO_FOLDER The folder icon, must be combined with BC_BTN_ICON
BC_ICO_EXPLORER The Windows Explorer icon, must be combined with BC_BTN_ICON

To set the "Windows Explorer" icon on the browse button, make the button flat, and finally, make the control "Browse for Folders" only:

C++
DWORD dwStyle = m_wndBrowseCtrl.GetButtonStyle();
dwStyle |= BC_BTN_ICON; // Make sure to display icon instead of text
dwStyle |= BC_BTN_FLAT; // Flat button
dwStyle &= ~BC_ICO_ARROWFOLDER; // Remove other icons
dwStyle &= ~BC_ICO_FOLDER;
dwStyle |= BC_ICO_EXPLORER; // Set the explorer icon
dwStyle |= BC_CTL_FOLDERSONLY; // Browse for folders only
m_wndBrowseCtrl.SetButtonStyle(dwStyle); // Apply

I've got tired of images and want the browse button to display text, say, "Click Me!", also make it display tooltip "Click to browse your files.":

C++
m_wndBrowseCtrl.SetButtonStyle(m_wndBrowseCtrl.GetButtonStyle() & ~BC_BTN_ICON);
m_wndBrowseCtrl.SetButtonText(_T("Click Me!"));
m_wndBrowseCtrl.SetTooltipText(_T("Click to browse your files."));

Browsing for Files and Folders

CBrowseCtrl handles the button events by itself so whenever the user clicks on the browse button, a file or folder dialog is popped up automatically. You can, of course, programmatically handle it in your code also, usually you may want to initialize the file dialog using whatever you would pass into the CFileDialog constructor. CBrowseCtrl provides a set of functions to allow doing the same initialization, you basically can just treat the control as a dialog:

C++
m_wndBrowseCtrl.SetOpenSave(TRUE); // TRUE-"open", FALSE-"save as"
m_wndBrowseCtrl.SetDefExt(NULL); // Do not use any default extension
m_wndBrowseCtrl.SetFilter(_T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*||"));
m_wndBrowseCtrl.SetFileFlags(OFN_FILEMUSTEXIST | OFN_HIDEREADONLY);
m_wndBrowseCtrl.SetPathName(_T("c:\\MyApp\\readme.txt")); // default path

if (m_wndBrowseCtrl.DoModal() == IDOK)
    MessageBox(m_wndBrowseCtrl.GetPathName());

To browse for folders:

C++
m_wndBrowseCtrl.SetButtonStyle(m_wndBrowseCtrl.GetButtonStyle() 
                                            | BC_CTL_FOLDERSONLY);
// Display an editbox on the dialog
m_wndBrowseCtrl.SetFolderFlags(BIF_EDITBOX); 
m_wndBrowseCtrl.SetFolderDialogTitle(_T("Please select a folder"));

if (m_wndBrowseCtrl.DoModal() == IDOK)
    MessageBox(m_wndBrowseCtrl.GetPathName());

And if the user has selected multiple files from the file dialog, you can iterate through all path names by the following code:

C++
if (m_wndBrowseCtrl.GetSelectedCount() > 1)// Multiple files selected
{
    POSITION pos = m_wndBrowseCtrl.GetStartPosition();
    while (pos != NULL)
    {
        CString sPathName = m_wndBrowseCtrl.GetNextPathName(pos);
        // Process the path name...
    }
}

Notifying the Parent Window

After the file/folder dialog is closed by the user, a notifying message is sent to the parent window. The wParam is either IDOK or IDCANCEL, the lParam is a pointer to this CBrowseCtrl object.

To make the control notify the parent window, you need to provide CBrowseCtrl, a custom window message which is greater than 0. If the message you provide is 0, the message will not be sent. If you do not provide any message, no message will be sent either.

C++
#define WM_BROWSE_NOTIFY WM_APP + 100
m_wndBrowseCtrl.SetNotifyMessageID(WM_BROWSE_NOTIFY);
// Now ready to receive the notification!

Conclusion

So that's about it. It is a nice little control to have around, I hope it could help you in some cases. Any suggestions are welcome, thanks for your time.

History

Jan 08, 2004

  • Initial release

Jan 09, 2004

  • Improved drawing functions to properly handle the case in which the control client area is too small to be drawn. In debug mode, it will provide a message box to inform the developer about that issue.
  • Improved the edit box so it acts better upon receiving and losing the input focus
  • Updated the source code and demo project

Jan 10, 2004

  • Fixed a problem where the edit box is not properly redrawn upon certain events. Thanks to JOHN11
  • Added method CBrowseCtrl::GetSelectedCount which returns the number of items the user has selected in the most recent file/folder dialog that was terminated by IDOK
  • Improved the mouse/focus events monitoring functions
  • Fixed a drawing glitch which could occur when the user clicks on the edges of the edit box
  • Changed the drawing-area calculating methods for performance improvement
  • Updated the source code and demo project

Jan 14, 2004

  • Updated SetPathName and GetPathName member functions
  • Altered the message sending method so the lParam is now a pointer to this CBrowseCtrl object
  • Updated the source code and demo project

Jan 22, 2004

  • Added methods to monitor whether the user has manually changed the contents of the edit box when BC_CTL_ALLOWEDIT is set. The return value of GetPathName will also be properly affected.
  • The window titles of file/folder dialogs can now be accessed by calling SetDialogTitle and GetDialogTitle.
  • The banner text of folder dialogs can now be accessed by calling SetDialogBanner and GetDialogBanner.
  • Added method ModifyButtonStyle to allow convenient style changing

Feb 07, 2004

  • Improved drawing functions so that images/text on the browse button are partially drawn if there is not enough space.

May 22, 2004

  • Updated drawing functions
  • Added functions: GetDriveLetter, GetDirectory, GetFileName, GetFileTitle, GetFileExt

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.


Written By
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralLicense Pin
Lars Wetzel15-May-11 22:27
Lars Wetzel15-May-11 22:27 
GeneralUsed in dotNetInstaller Pin
dB.18-Oct-09 15:41
dB.18-Oct-09 15:41 
GeneralAlt key causes to draw the control like a button Pin
jmaldarondo18-Aug-08 4:04
jmaldarondo18-Aug-08 4:04 
GeneralHow Pin
Kryptech20-Jun-07 8:51
Kryptech20-Jun-07 8:51 
Generalbind to CBrowseCtrl Pin
jmhill2317-Apr-07 20:24
jmhill2317-Apr-07 20:24 
GeneralRe: bind to CBrowseCtrl Pin
davy77710-May-07 13:27
davy77710-May-07 13:27 
GeneralRe: bind to CBrowseCtrl Pin
jmhill2315-May-07 8:30
jmhill2315-May-07 8:30 
GeneralRe: bind to CBrowseCtrl Pin
jmhill2315-May-07 20:20
jmhill2315-May-07 20:20 
GeneralRe: bind to CBrowseCtrl Pin
Duely24-Oct-09 9:00
Duely24-Oct-09 9:00 
GeneralCBrowseCtrl with own icon Pin
dressman19818-Mar-07 2:23
dressman19818-Mar-07 2:23 
Generalmultiple browse buttons Pin
Anxnahlia12-Jan-07 1:47
Anxnahlia12-Jan-07 1:47 
GeneralRe: multiple browse buttons Pin
Abin14-Jan-07 17:23
Abin14-Jan-07 17:23 
GeneralBrilliant Pin
obriengearoid23-Jun-05 0:31
obriengearoid23-Jun-05 0:31 
General[Message Deleted] Pin
Anonymous15-May-05 8:59
Anonymous15-May-05 8:59 
GeneralRe: Any simpler code?! Pin
bassam.mehanni1-Aug-06 3:57
bassam.mehanni1-Aug-06 3:57 
GeneralRelease Mode Crashes Pin
j.jonez23-Jan-05 12:59
j.jonez23-Jan-05 12:59 
GeneralSetting the text in the File Name edit control Pin
Girays2-Jan-05 0:10
Girays2-Jan-05 0:10 
GeneralRe: Setting the text in the File Name edit control Pin
HTKim15-Jan-05 7:31
HTKim15-Jan-05 7:31 
QuestionFont bug? Pin
Member 158673530-Dec-04 7:03
Member 158673530-Dec-04 7:03 
AnswerRe: Font bug? Pin
Abin25-Jul-05 19:33
Abin25-Jul-05 19:33 
GeneralSmall bug in GetNextPathName() Pin
eFotografo10-Sep-04 0:43
professionaleFotografo10-Sep-04 0:43 
There's a small bug in GetNextPathName() which allows the return of an empty string *before* the pos variable is set to NULL. The fix is quite simple. Just replace the GetNextPathName() method as follows:

CString CBrowseCtrl::GetNextPathName(POSITION &pos) const
{
    // Make sure pos is a valid position
    if (pos == NULL)
        return _T("");

    if (IsEditManuallyChanged())
    {
        // contents of the edit box has been changed by direct user input
        POSITION posOrig = pos;
        pos = NULL;
        return (DWORD)posOrig == (DWORD)(LPCTSTR)m_sEditText ? m_sEditText : _T("");
    }

    if (m_lpszPathNames == NULL
        || m_nPathNamesLen == 0
        || m_nSelCount == 0
        || (DWORD)pos < (DWORD)m_lpszPathNames
        || (DWORD)pos >= (DWORD)m_lpszPathNames + (DWORD)m_nPathNamesLen)
    {
        pos = NULL;
        return _T("");
    }

    // FIX: ensure pos is set to NULL when the last file has been read
    LPCTSTR p = (LPCTSTR)pos;
    const int LEN = _tcslen(p);
    if ((LEN == 0) || (p[LEN + 1] == NULL))
    {
        pos = NULL;
    }
    else
    {
        pos = (POSITION)(&p[LEN + 1]); // Advance the pointer to next file name
    }
    return p;
}


Fixing this also allows a single loop construct to be used to process either individual or multiple files:

for (POSITION pos = m_wndBrowseCtrl.GetStartPosition(); pos != NULL; )
{
    CString strFile = m_wndBrowseCtrl.GetNextPathName(pos);

	// do something with the file
}


Enjoy,

John
Generalif it allow to create folder, that will be better. Pin
jancook27-May-04 7:38
jancook27-May-04 7:38 
AnswerRe: if it allow to create folder, that will be better. Pin
davedrums6-Nov-08 9:37
davedrums6-Nov-08 9:37 
GeneralNice, but... Pin
pgiustinoni2-Apr-04 23:39
pgiustinoni2-Apr-04 23:39 
GeneralRe: Nice, but... Pin
Abin4-Apr-04 1:29
Abin4-Apr-04 1:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.