📄 cb199910dc_f.asp.htm
字号:
view (file size, description, and modification time): This feature may not be
necessary for all situations; however, some applications may require such information.
Further, many users require items to be sorted by these criteria. (Priority
rank = 50 percent)
<li>Directional
sorting: As mentioned, many users use a sorted view to quickly access certain
items. If the Details view is to be supported, it's essential to implement
directional sorting. (Priority rank = 50 percent)
<li>Header
dragging and dropping (column rearrangement): There are few instances where
column rearrangement increases the usability of the Explorer interface. Its
chances of being used are further lowered because it only applies to the
Details view. (Priority rank = 30 percent)
<li>Hot
tracking and variable-click selection: While the former is more for visual
effect and adds little functionality to the control, the latter has been
adopted by many users, especially those who've adapted to the single-click, or
have difficulty otherwise. Indeed, this feature applies to all view styles.
(Priority rank = 75 percent)
<li>Automatic
program launch: Like the context menu, this feature may have inherited a loyal
following. Consider this case: A user wants to quickly view the contents of a
document or compressed file before performing an action on it. If the user
activates and selects the item expecting the corresponding application to open
the indicated file and nothing happens, he or she may become irritated or
suspicious of system lock. (Priority rank = 75 percent)
</ul>
<p class=BodyText> </p>
<p class=BodyText> Keep in
mind that this list and each item's corresponding priority number is not set in
stone. In fact, we may find some of these features nearly impossible to
implement without a complete re-write of the underlying control. While these
priority ranks serve as a good indication of what needs to be accomplished, and
in what order, the implementation stages may prove otherwise. There's nothing
wrong with changing a design during implementation; it is, in fact, necessary
for most developers to reconsider design issues several times after much coding
has been completed. </p>
<p class=BodyText> </p>
<p class=Subheads>Choosing an
Implementation Scheme</p>
<p class=BodyText> Now that
we've prioritized the necessity of each of the key features, we need to choose
a method to perform the most fundamental goal: filling the ListView with items
from any given folder. The first solution that comes to mind involves the <i
style='mso-bidi-font-style:normal'>FindFirst</i> and <i>FindNext</i> methods. These are simply VCL wrappers of the API <i
style='mso-bidi-font-style:normal'>FindFirstFile</i> and <i>FindNextFile</i> functions. A typical implementation to fill a <i
style='mso-bidi-font-style:normal'>TListView</i> using the <i>FindFirst</i> and <i>FindNext</i>
functions is shown in Figure 2. </p>
<p class=BodyText> </p>
<p class=Code><span class=Code><b>void</b> <b
style='mso-bidi-font-weight:normal'>__fastcall</b> TForm1::FillListEx()</span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> SHFILEINFO IconInfo; </span></p>
<p class=Code><span class=Code> <b> char</b>
path[MAX_PATH]; </span></p>
<p class=Code><span class=Code> TSearchRec SearchRecord; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Bind ImageList1 to the system image list. </span></i></span></p>
<p class=Code><span class=Code> ImageList1->ShareImages = <b
style='mso-bidi-font-weight:normal'>true</b>;</span></p>
<p class=Code><span class=Code> ImageList1->Handle = SHGetFileInfo(</span></p>
<p class=Code><span class=Code> "", 0, &IconInfo, <b
style='mso-bidi-font-weight:normal'>sizeof</b>(IconInfo), </span></p>
<p class=Code><span class=Code> SHGFI_ICON | SHGFI_SMALLICON |
SHGFI_SYSICONINDEX); </span></p>
<p class=Code><span class=Code> ListView1->SmallImages = ImageList1; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Prevent screen updating. </span></i></span></p>
<p class=Code><span class=Code> ListView1->Items->BeginUpdate();</span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Locate the first file in the desktop directory. </span></i></span></p>
<p class=Code><span class=Code> <b> if</b>
(FindFirst("C:\\Windows\\Desktop\\*.*", </span></p>
<p class=Code><span class=Code> faAnyFile, SearchRecord) == 0) </span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Add a new item, then assign the located</span></i></span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// filename to its Caption property. </span></i></span></p>
<p class=Code><span class=Code> TListItem *Item =
ListView1->Items->Add();</span></p>
<p class=Code><span class=Code> Item->Caption = SearchRecord.Name; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Retrieve the index in the imagelist corresponding</span></i></span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// to the Explorer-type icon of a given filename, then</span></i></span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// assign it the ImageIndex property of the new item. </span></i></span></p>
<p class=Code><span class=Code> AnsiString Path =
"C:\\Windows\\Desktop\\" + Item->Caption; </span></p>
<p class=Code><span class=Code> strcpy(path, Path.c_str()); </span></p>
<p class=Code><span class=Code> SHGetFileInfo(path, 0, &IconInfo, <b
style='mso-bidi-font-weight:normal'>sizeof</b>(IconInfo), </span></p>
<p class=Code><span class=Code> SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SYSICONINDEX); </span></p>
<p class=Code><span class=Code> Item->ImageIndex = IconInfo.iIcon; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Repeat this process for the rest of the files. </span></i></span></p>
<p class=Code><span class=Code> <b> while</b>
(FindNext(SearchRecord) == 0) </span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> Item = ListView1->Items->Add();</span></p>
<p class=Code><span class=Code> Item->Caption = SearchRecord.Name; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> Path = "C:\\Windows\\Desktop\\"
+ Item->Caption; </span></p>
<p class=Code><span class=Code> strcpy(path, Path.c_str());</span></p>
<p class=Code><span class=Code> SHGetFileInfo(path, 0, &IconInfo, <b
style='mso-bidi-font-weight:normal'>sizeof</b>(IconInfo), </span></p>
<p class=Code><span class=Code> SHGFI_ICON |
SHGFI_SHELLICONSIZE |</span></p>
<p class=Code><span class=Code> SHGFI_SYSICONINDEX); </span></p>
<p class=Code><span class=Code> Item->ImageIndex = IconInfo.iIcon; </span></p>
<p class=Code><span class=Code> } </span></p>
<p class=Code><span class=Code> } </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Close the search handle. </span></i></span></p>
<p class=Code><span class=Code> FindClose(SearchRecord); </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Restore screen updating. </span></i></span></p>
<p class=Code><span class=Code> ListView1->Items->EndUpdate();</span></p>
<p class=Code><span class=Code>}</span></p>
<p class=Captions><b>Figure
2:</b> Code
demonstrating the use of <i>FindFirst</i> and <i>FindNext</i>.</p>
<p class=BodyText> </p>
<p class=BodyText> Before
putting this code into a component, let's test it in a simple project
containing a blank form and a single <i>TListView</i>.
After adding the necessary functions, we find that the approach is relatively
quick, although not nearly as fast as Explorer. Testing this code on different
directories containing various amounts of files, we notice that the bottleneck
in this procedure is caused by the <i>TListItems::Add</i>
method. In fact, by commenting out this single line, we find the enumeration
code to be nearly instantaneous. In Part II of this series, we'll discuss some
techniques to overcome this bottleneck. </p>
<p class=BodyText> </p>
<p class=BodyText> At this
point, we notice what seems to be a minor issue; namely, that certain objects
and their corresponding icons fail to appear in our ListView. For example, when
enumerating the Desktop folder, we find that objects such as My Computer,
Network Neighborhood, and Recycle Bin fail to appear. Upon examination of the
documentation for the <i>FindFirstFile</i>
function, we see there is no flag to set to make these objects appear. As a
test, we execute a <i>TOpenDialog</i> and
choose the Desktop folder. Indeed, in this common dialog wrapper, these icons
appear as expected. However, we also notice that these objects don't appear to
be physical file objects. That is, they cannot be dragged into a separate
folder or simply deleted. Why then, don't they appear in our ListView, as we
are using two of the most common API file-manipulation functions? </p>
<p class=BodyText> </p>
<p class=BodyText> These
objects, in fact, represent a special class of folders known as <i>virtual</i>
folders. They are not maintained by the file system itself, rather by the shell
namespace and several OLE COM interfaces. While many developers find the COM
intimidating, it turns out that to work with the shell namespace, we only need
to use a few COM interfaces. </p>
<p class=BodyText> </p>
<p class=Subheads>Working
with the Shell Namespace</p>
<p class=BodyText> While an
in-depth discussion of the shell namespace and COM itself are well beyond the
scope of this article, we'll briefly discuss those interfaces and shell
functions that we'll use to fill our ListView. The first and most important is
the <i>IMalloc</i> COM interface. Although
this interface has several methods, the one we're primarily interested in (the
one we'll use extensively) is the <i>IMalloc::Free</i>
method. This is simply used to free any blocks of memory previously allocated
by the shell. To get a pointer to this interface, we use the shell namespace <i
style='mso-bidi-font-style:normal'>SHGetMalloc</i> function. </p>
<p class=BodyText> </p>
<p class=BodyText> Another
interface that's commonly used is <i>IShellFolder</i>.
As the name suggests, this interface manages shell folder objects. The <i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -