Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A compact filename edit control

0.00/5 (No votes)
4 Feb 2003 3  
An edit control that encapsulates compacting of filenames

Sample Image - CompactFilename.gif

Introduction

Often in applications, there is a need to show a filename, for example in a read only edit control. However, the filename maybe larger than can be accommodated in the edit control. Many Microsoft applications show the filename "compacted", whereby part of the path is replaced by ellipsis ("..."). The need arose to do the same for the application that I am currently developing. My solution, presented below, was to create my own class, based on the MFC CEdit control, to handle the filename appropriately.

Path compaction

A short investigation into how to go about compacting the path led me to the function PathCompactPath(). This function is part of the shlwapi.dll, which means that it is not available on systems running Windows 95 or Windows NT unless Internet Explorer 4.,0 or greater is installed. Fortunately, this covered all of the users of our system, and I would imagine it covers most users of 32 bit Windows operating systems.

Using the function is exceedingly simple. It takes three parameters, an HDC, the filename to compact, and the amount of space the text is to fit into. Therefore, to compact the path sufficiently to fit into the edit control, we simply use the following code :

CString CFilenameEdit::GetDisplayName()
{
    // Get the DC for the control, and the rectangle into which we draw text

    CDC * pDC = GetDC();
    CRect rectClient;
    GetRect(&rectClient);

    // Select the correct font into the DC

    CFont * pFontOld = pDC->SelectObject(GetFont());

    // Get the display name, and truncate it to fit into the control

    // Note that we make the buffer larger than max path 

    // in case we have some bizarre

    // situation where a load of ellipsis are inserted 

    // and it overruns the buffer

    // Member variable containing filename; set by caller

    CString strDisplayName = m_strFilename; 
    PathCompactPath(pDC->GetSafeHdc(),
                    strDisplayName.GetBuffer(_MAX_PATH + 1 + BUFFER_EXTRA),
                    rectClient.Width());
    strDisplayName.ReleaseBuffer();

    // Clean up!

    pDC->SelectObject(pFontOld);
    ReleaseDC(pDC);

    return strDisplayName;
}

Note that we have to select the correct font (obtained by calling CEdit::GetFont()) into the DC, before using the function, otherwise the incorrect font is used when determining the text length.

A concern was that, the function would return a string longer than _MAX_PATH characters, in which case we would suffer buffer overrun. This could happen in the case that the ellipsis (essentially three period characters) had a shorter text extent than two characters, and hence two characters in the string were replaced by three. Hence, the call to CString::GetBuffer() requests a slightly larger buffer, just in case!

Using the control

CFilenameEdit, derived from CEdit, is designed to be read only, the idea being that the filename can be set by the parent application, say for example when a user selects a file from a CFileDialog.

The control has just two public functions, SetFilename() and GetFilename, which set and retrieve the filename to be displayed. The call to SetFilename() maintains an internal copy of the full filename, and sets the control text to the compacted filename, obtained using the code above. GetFilename retrieves the full filename, regardless of how it is compacted in the control.

Because the control text will differ from the filename that is to be displayed, the normal DDX_Text routines are no good - when the text is loaded into the control, the full filename will be placed in the control. Similarly, if the compacted filename is displayed in the control, this is exactly what the DDX_Text routine will return when saving the content of the control. Hence, in addition to the control, there is also a DDX_??? routine, DDX_Filename, which calls the SetFilename() and GetFilename() functions accordingly.

As a visual aid to the user, a tooltip control is created. When the mouse hovers over the control, the tooltip displays the complete path.

Demonstration project

The demonstration project has two edit controls, one of which has been subclassed to provide the CFilenameEdit functionality. The other is a standard edit control, which can be used to compare the contents of the controls when a filename is placed into them.

The Browse button allows a file to be chosen, the name of which will be shown in both edit controls. The Get Content button displays the filename shown in the filename edit control, proving that the DDX_Filename routine works correctly.

Conclusion

The control as it stands is exactly what was need for the application I am currently developing. There are so many things that could be added to it, and maybe when I get chance I will add more. Other articles here show how to make the control accept files that have been dragged and dropped onto it, and how to build a Browse button into the control - both ideas that could be incorporated to enhance this control.

At this point, I really ought to pass on my thanks to Roger Allen, whose snippet of information about setting the font in the DC before calling PathCompactPath made the result somewhat more accurate!

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