⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cb200006dc_f.asp.htm

📁 C++builder学习资料C++builder
💻 HTM
📖 第 1 页 / 共 5 页
字号:


<HTML>

  <HEAD>

<TITLE>Exploring Possibilities</TITLE>

   

  </HEAD>

  <BODY>

  <TABLE border=0 width="100%" cellpadding=0 cellspacing=0>

<TR valign=top>

<TD width="100%">



 

<p class=ColumnTitle><font size="2">In  

Development</font></p>  

  

<p class=ColumnSubtitle>Development  

Strategies / Component Design and Creation / User Interface Issues</p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Byline>By Damon       

Chandler</p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=StoryTitle><font size="2"><b>Exploring       

Possibilities</b></font></p>       

       

<p class=StorySubtitle><font size="2">Part       

II: Wrapping Up Our List View Component</font></p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> Before       

we continue our examination of the process of creating an Explorer-style list       

view control, let's recap the main concepts from Part I of this series. Our       

goal is to create a familiar, intuitive means for users of our component to       

interact with the Windows shell. To this end, we chose to create a <i       

style='mso-bidi-font-style:normal'>TCustomListView</i> descendant class that       

emulates the folder view (i.e. the left pane) of Windows Explorer. Moreover, we       

decided that such a class was ideally suited for presentation as a VCL       

component. We also covered some of the initial design strategies, and prepared       

a prioritized list of features to implement. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> Again,       

our first, and fundamental task, is to fill the list view control with shell       

objects. That is, we need to populate our list view with items that represent       

the files, folders, and virtual objects of the shell namespace. However, a key       

realization made in Part I is that we cannot use the traditional approach       

involving the <i>FindFirst</i> and <i       

style='mso-bidi-font-style:normal'>FindNext</i> functions. Recall that these       

functions will only work with those shell objects that are part of the physical       

file system. To overcome this limitation, we examined several shell API       

structures, functions, and interfaces. Specifically, we related a file object's       

name and path to the SHITEMID and ITEMIDLIST structures, respectively. We also       

discussed the use of the <i>IShellFolder</i>       

and <i>IEnumIDList</i> interfaces, and       

examined how these interfaces can be used to enumerate the contents of a       

folder. Again, the advantage of these interfaces over the traditional approach       

lies in the fact that they can be used with virtual folders (e.g. Control Panel),       

as well as file-system folders. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> Finally,       

recall that during the process of populating the list view, we ran into another       

problem. Namely, we discovered that our enumeration process was not nearly as       

fast as that of Windows Explorer. Let's examine some techniques to help us       

overcome this speed limitation. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=Subheads>Breaking       

the Speed Limit</p>       

       

<p class=BodyText> With the       

introduction of COMCTL32.DLL version 4.70, Microsoft presented the       

LVS_OWNERDATA list view style. Use of this style creates what is known as a       

virtual list view, available in the <i>TCustomListView</i>       

class via the <i>OwnerData</i> property.       

This style affords significant speed improvements, but presents several       

limitations of its own. For example, virtual list views don't support multiple       

work areas, specification of item position (LVM_SETITEMPOSITION; <i       

style='mso-bidi-font-style:normal'>TListItem::Position</i>), or "snap-to-grid" arrangement, among others. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> Another       

way of decreasing the amount of time necessary to adding an item, is to specify       

LPSTR_TEXTCALLBACK and I_IMAGECALLBACK as values for the <i>pszText</i> and <i>iImage</i>       

parameters of the LVITEM structure, respectively. Use of these flags simply       

frees the list view from storing the data associated with each of these fields.       

Accordingly, the list view's parent window is required to handle the       

LVN_GETDISPINFO notification message to supply the necessary data. This is the       

same approach taken by the <i>TCustomListView</i>       

class. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> Since       

the virtual list view suffers from too many limitations, let's take advantage       

of the second approach. Namely, we'll emulate Windows Explorer by providing       

information on a need-to-know basis. For example, when browsing a directory       

containing a large amount of items, only a small fraction is initially visible.       

As the LVN_GETDISPINFO notification message is sent only for those items that       

are visible, it would make sense to retrieve an item's information in response       

to this message. Moreover, this information only needs be retrieved once,       

because we can store the results and supply the cached information upon       

request. To this end, let's create a simple class that will hold the relevant       

information for each shell object. Such a class is shown in <a       

href="#ListingOne">Listing One</a>.</p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> While we       

now have an element class, we still need an associated container class. Here,       

we'll simply use the <i>TListItem::Data</i> property. Note, however,       

that the <i>TList</i> VCL class, or one of       

the container classes from the Standard C++ Library, is also a viable, more       

robust, candidate. Let us now revise the <i>FillListEx</i>       

by implementing its component-based counterpart, the virtual <i       

style='mso-bidi-font-style:normal'>DoFillListEx</i> member function, as shown       

in <a href="#ListingTwo">Listing Two</a>.</p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> The <i>TExpListView::DoFillListEx</i>       

member function is similar to the <i>FillListEx</i>       

function, except we've eliminated the expensive <i>SHGetFileInfo</i> function call. Instead, we create an instance of the <i       

style='mso-bidi-font-style:normal'>TListShellInfo</i> class, then query the       

component user for permission to add the item. In this way, the component user       

can appropriately filter out certain items. Once an item is added, we use the <i       

style='mso-bidi-font-style:normal'>DisplayNameFromPIDL</i> utility function to       

retrieve the associated display name of the shell object, and store a pointer       

to the <i>TListShellInfo</i> instance in the       

<i>Data</i> property of the newly added <i>TListItem</i>.</p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> Our next       

task is to handle the LVN_GETDISPINFO notification message. This message is       

sent to the parent of the list view in the form of a WM_NOTIFY message. To handle       

this message in our component class, we provide a handler for the CN_NOTIFY       

message. This latter message is simply a reflected version of WM_NOTIFY that is       

sent back to the list view itself. In response to the LVN_GETDISPINFO       

notification message, we determine the item for which information is being       

requested, then simply fill its associated <i>TListShellInfo</i>       

instance with relevant shell information. This latter task is delegated to the       

virtual <i>DoFillShellInfoIcon</i> and <i       

style='mso-bidi-font-style:normal'>DoFillShellInfoDetails</i> member functions,       

for icon and details view (e.g. size, type, date) information retrieval,       

respectively. The implementations of these member functions, along with the       

CN_NOTIFY message handler, are shown in <a href="#ListingThree">Listing Three</a>.</p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> It's       

important to note that we only need to extract the shell information for a       

certain item if that item is visible in the list view. This part is handled       

automatically by the LVN_GETDISPINFO message handler. That is, the notification       

message is only sent for visible items. Once this information is obtained,       

there's no need to extract it again. To this end, the <i>TListShellInfo</i>::<i>ValidIcon</i>       

and <i>ValidDetails</i> properties serve as       

flags, indicating whether the shell information for a particular item has       

already been retrieved. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> Finally,       

there's somewhat of a cause-and-effect paradox when using the <i       

style='mso-bidi-font-style:normal'>TListItem</i> class. Namely, in response to       

the LVN_GETDISPINFO message, we extract, then assign, the proper icon index to       

the <i>TListItem::ImageIndex </i>property. Yet, when the <i>ImageIndex</i> property is changed, the <i>TListItem</i> class calls the <i>TCustomListView::UpdateItems</i> member function,       

causing our list view to receive yet another LVN_GETDISPINFO notification.       

Figure 1 illustrates this conundrum. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=Captions><img width=330 height=241       

 src="images/cb200006dc_f_image001.gif" tppabs="http://www.cbuilderzine.com/features/2000/06/cb200006dc_f/cb200006dc_f_image001.gif"> <br>       

<b>Figure 1:</b> The "cause-and-effect" paradox. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

       

       

<p class=BodyText> While       

our <i>ValidIcon</i> property effectively       

prevents an infinite cycle, this is certainly not efficient. To prevent this,       

we simply trap the first LVN_GETDISPINFO notification, and provide the       

information to the list view in response to the incited version, i.e. the       

LVN_GETDISPINFO notification caused by manipulating the <i>ImageIndex</i> property. This is effectively handled with the following       

statement from the <i>CNNotify</i> message       

handler: </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=Code><span class=Code><b>if</b> (DoFillShellInfoIcon(RequestItem)) </span></p>       

       

<p class=Code><span class=Code>&nbsp;&nbsp;<b> return</b>;</span></p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=BodyText> We       

implement the <i>DoFillShellInfoIcon</i>       

member function to return <b>true</b> if the <i>TListItem</i>::<i>ImageIndex</i>       

property has been set. Because we know this manipulation will incite another       

LVN_GETDISPINFO message, we can simply trap the first message. A similar       

technique is used for the details information, where manipulation of the <i       

style='mso-bidi-font-style:normal'>TListItem::SubItems </i>property invokes an LVN_GETDISPINFO notification       

message as well. Figure 2 depicts the corrected scheme. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

<p class=Captions><img width=330 height=241       

 src="images/cb200006dc_f_image002.gif" tppabs="http://www.cbuilderzine.com/features/2000/06/cb200006dc_f/cb200006dc_f_image002.gif"> <br>       

<b>Figure 2:</b> The "cause-and-effect" solution. </p>       

       

<p class=BodyText> &nbsp; </p>       

       

       

       

<p class=Subheads>Handling       

the Details View</p>       

       

<p class=BodyText> Notice       

from the <i>DoFillShellInfoDetails</i>       

implementation of Listing Three that we use the <i>IShellDetails</i> interface to retrieve the "details view" information       

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -