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.
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 :
CDC * pDC = GetDC();
CFont * pFontOld = pDC->SelectObject(GetFont());
CString strDisplayName = m_strFilename;
strDisplayName.GetBuffer(_MAX_PATH + 1 + BUFFER_EXTRA),
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
The control has just two public functions,
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_Filename, which calls the
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.
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.
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!