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

📄 cb200006dc_f.asp.htm

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

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

       

<p class=BodyText> We       

provide support for context menus in our class via the <i>DoShowContextMenu</i>, <i>WMContextMenu</i>,       

and <i>WMContextMenu2</i> member functions,       

as shown in <a href="#ListingSeven">Listing Seven</a>.       

The former handles the details we've just discussed. The <i>WMContextMenu</i> member function is simply a message handler for the       

WM_CONTEXTMENU message. The <i>WMContextMenu2</i>       

member function handles the popup menu and owner-drawn messages that are sent       

through the use of the <i>IContextMenu2</i>       

interface. Specifically, the member function handles the WM_DRAWITEM,       

WM_MEASUREITEM, and WM_INITMENUPOPUP messages. The actual task of rendering the       

owner-drawn menu items is delegated to the <i>IContextMenu2</i>       

interface itself, via the <i>IContextMenu2:: HandleMenuMsg</i> member function. </p>       

       

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

       

<p class=BodyText> To help       

fortify the techniques of using the <i>IContextMenu</i>       

and <i>IContextMenu2</i> interfaces, refer       

to the DemoContextMenu sample project (also included with the downloadable       

source code). In this project, the task of displaying an item's context menu is       

isolated from the rest of the <i>TExpListView</i>       

implementation. </p>       

       

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

       

<p class=Subheads>Launching       

an Item's Associated Application</p>       

       

<p class=BodyText> Since       

we've associated a <i>TListShellInfo</i>       

instance with each <i>TListItem</i> object,       

we have access to the absolute and relative PIDLs of each shell object within       

our list view. Accordingly, to launch an item's associated application, we can       

simply use the <i>ShellExecuteEx</i> API       

function with the SEE_MASK_INVOKEIDLIST flag. Use of this flag simply instructs       

the function that the <i>SHELLEXECUTEINFO:: lpIDList </i>data member contains       

the fully qualified PIDL of the item we wish to execute. Support for this       

functionality is provided in our class via the <i>DoLaunchItem</i> and <i>LaunchItem</i>       

member functions. The former simply calls the latter, which uses the <i       

style='mso-bidi-font-style:normal'>ShellExecuteEx</i> function. These member       

functions are shown in <a href="#ListingEight">Listing Eight</a>.</p>       

       

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

       

<p class=BodyText> Notice       

from the implementation of the <i>LaunchItem</i>       

member function that we provide special handling for the situation when the       

shell item is a shortcut. In such a case, we cannot simply assign the item's       

absolute PIDL to the <i>lpIDList</i> data       

member, because the PIDL refers to the link object itself, not the object to       

which the shortcut refers. Instead, we use the <i>GetLinkPIDL</i> function (from the "pidlhelp" library) to de-reference       

the link object, then assign this result to the <i>lpIDList</i> data member. </p>       

       

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

       

<p class=Subheads>Receiving       

Notification of Changes</p>       

       

<p class=BodyText> While we       

now have a robust means of filling our list view and managing the items that it       

contains, we still need a method of receiving notification of changes to any of       

the objects that are represented. For file system objects, we can simply use       

the <i>FindFirstChangeNotification</i> and <i       

style='mso-bidi-font-style:normal'>FindNextChangeNotification</i> API       

functions, in conjunction with the <i>WaitForMultipleObjects</i>       

API function. This latter function will literally wait for notification (from       

the file system) of a change event. The "waiting" process is typically handled       

in a separate thread to allow the main thread to continue processing messages.       

To this end, we can simply create a <i>TThread</i>       

descendant class, and place the <i>WaitForMultipleObjects</i>       

function call in the <i>Execute</i> member       

function. For a detailed discussion of this process, including the specifics of       

the <i>TThread</i> descendant class, refer       

to the sample project <span Class=CodeBlue><a       

href="javascript:if(confirm('http://bcbcaq.freeservers.com/Project_Monitor.html  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://bcbcaq.freeservers.com/Project_Monitor.html'" tppabs="http://bcbcaq.freeservers.com/Project_Monitor.html">http://bcbcaq.freeservers.com/Project_Monitor.html</a>.</span><i></i></p>       

       

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

       

<p class=BodyText> Unfortunately,       

the aforementioned technique will not work for virtual folders; the <i       

style='mso-bidi-font-style:normal'>FindFirstChangeNotification</i> function requires       

a file system path. In fact, there's no documented means by which we can       

monitor the contents of a virtual folder without some type of polling       

technique. As it turns out, there is an undocumented alternative, via the <i       

style='mso-bidi-font-style:normal'>SHChangeNotifyRegister</i> function, exported       

from SHELL32.DLL with an ordinal value of two. While the use of this function       

is open to interpretation, Bluck and Holderness have prepared a comprehensive       

treatment in the article found at <span Class=CodeBlue><a       

href="javascript:if(confirm('http://www.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp  \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address.  \n\nDo you want to open it from the server?'))window.location='http://www.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp'" tppabs="http://www.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp">http://www.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp</a>.</span></p>       

       

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

       

<p class=Subheads>Design-time       

Considerations</p>       

       

<p class=BodyText> Now that       

the run-time functionality is in place, let's consider some design-time issues.       

We have one published property, <i>Folder</i>, that needs a property editor.       

Instead of requiring the user to type in an absolute path just to change       

directories, let us display a simple "Browse for Folder" dialog box, as       

depicted in Figure 4. By using the <i>SHBrowseForFolder</i>       

API function, we can obtain an absolute PIDL for the chosen folder. Moreover,       

this will allow easy selection of virtual folders. </p>       

       

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

       

<p class=Captions><img width=333 height=214       

src="images/cb200006dc_f_image006.jpg" tppabs="http://www.cbuilderzine.com/features/2000/06/cb200006dc_f/cb200006dc_f_image006.jpg" align=left hspace=12><b>Figure 4:</b> The Folder property editor. </p>       

       

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

       

<p class=BodyText> For the       

property editor, we create a <i>TStringProperty</i>       

descendant class, <i>TPathEditor</i>, and       

implement three inherited member functions: <i>Edit</i>, <i>GetValue</i>, and <i>GetAttributes</i>.       

<i>GetAttributes</i> is used to indicate what property attributes to display in       

the Object Inspector. In this case, we return the <i>paDialog</i> and <i>paReadOnly</i>       

attributes. </p>       

       

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

       

<p class=BodyText> Within       

the <i>GetValue</i> member function, we       

return the string we want displayed in the Object Inspector's edit control       

field for the <i>Folder</i> property. Because most virtual folders will yield       

an empty string for the <i>Folder</i> property, we implement the <i       

style='mso-bidi-font-style:normal'>GetValue</i> member function to return the       

virtual folder's corresponding display name. This latter task is accomplished       

by the <i>DisplayNameFromPIDL</i> utility       

function. </p>       

       

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

       

<p class=BodyText> The <i       

style='mso-bidi-font-style:normal'>Edit</i> member is executed when the user       

clicks the ellipsis button that appears next to the Folder field (as a result       

of the <i>paDialog</i> attribute). It is       

from within this function that we call the <i>SHBrowseForFolder</i>       

API function, then assign the returned PIDL to the <i>PIDL</i> property of our       

component. <a href="#ListingNine">Listing Nine</a>       

provides the implementation of the <i>TPathEditor</i>       

class. </p>       

       

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

       

<p class=BodyText> Notice       

that we use a few additional PIDL-related utility functions in the       

implementation of our <i>TPathEditor</i>       

class. For example, we use the <i>CSIDLFromPIDL</i>       

utility function to retrieve a special folder constant identifier (the CSIDL_<i>XXX</i>       

values) from a PIDL. This conversion is necessary because we cannot rely on the       

display name of a virtual folder to yield its PIDL. Put another way, the "My       

Computer" object may be renamed "Jim Bob's Computer" on the end user's system.       

If we were to stream "My Computer" to the .dfm file on the development machine,       

the component will fail to return a PIDL from this display name on the end       

user's machine if there is no object with that particular display name. The       

only consistent references that we have are the CSIDL definitions. That is,       

CSIDL_DRIVES (the CSIDL constant for "My Computer") will work on any machine       

regardless of changes to the display name of the "My Computer" object. </p>       

       

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

       

<p class=Subheads>Conclusion</p>       

       

<p class=BodyText> Creating       

an Explorer-style list view control is by no means a weekend task. In fact,       

there are many more aspects yet to be "explored." One major feature that has       

been conveniently overlooked is drag-and-drop support. Like much of the implementation       

presented throughout this article, this requires the use of several additional       

COM interfaces. Other features, such as adding a background image, require less       

effort. While additional testing needs to be done before our component is       

deemed completely robust, the underlying principles are nonetheless sound. For       

example, a similar approach can be used to create an Explorer-style tree view       

control or an Explorer-style combo box. </p>       

       

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

       

<p class=BodyText> <i>The code referenced in this article is<b>       

</b>available for <a href="download/cb200006dc_f.zip" tppabs="http://www.cbuilderzine.com/features/2000/06/cb200006dc_f/cb200006dc_d.asp">download</a>. </i></p>     

     

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

     

<p class=Biotext>Damon Chandler       

has been programming for over 15 years, and enjoys every facet of the art.       

Mostly self-taught, Damon followed a common path to C++ programming - GW-BASIC,       

Pascal, then C++. It was the combination of the VCL and C++ that got him hooked       

on C++Builder. An engineer by trade and a programmer at heart, Damon is very       

pleased to see the two technologies finally merge. Damon is currently working       

in the Visual Communications Lab at Cornell University, where his research       

primarily centers around wavelet image compression. C++Builder is the tool of       

choice, and the RAD theme has helped create new interfaces for often obscure       

tasks. </p>       

       

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

       

<p class=Subheads><a name=ListingOne></a>Begin Listing One - The <i>TListShellInfo</i>       

class</p>       

       

<p class=Code><span class=Code><b>class</b>       

PACKAGE TListShellInfo : <b>public</b>       

TObject</span></p>       

       

<p class=Code><span class=Code>{</span></p>       

       

<p class=Code><span class=Code><b>private</b>:</span></p>       

       

<p class=Code><span class=Code>&nbsp;&nbsp;<i> <span Class=CodeBlue>// Path property. </span></i></span></p>       

       

<p class=Code><span class=Code>&nbsp;&nbsp;AnsiString <b>__fastcall</b> GetPath()<b>const</b></span></p>       

       

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

PathFromPIDL(m_FlpidlFQ); }</span></p>       

       

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

       

<p class=Code><span class=Code>&nbsp;&nbsp;<i> <span Class=CodeBlue>// AbsolutePIDL and RelativePIDL properties. </span></i></span></p>       

       

<p class=Code><span class=Code>&nbsp;&nbsp;LPITEMIDLIST m_FlpidlFQ; </span></p>       

       

<p class=Code><span class=Code>&nbsp;&nbsp;LPITEMIDLIST m_FlpidlRel; </span></p>       

       

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

       

<p class=Code><span class=Code>&nbsp;&nbsp;<i> <span Class=CodeBlue>// Attributes properties. </span></i></span></p>       

       

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

m_FIsVirtual; </span></p>       

⌨️ 快捷键说明

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