sorted_baseclass.shtml
来自「mfc资源大全包含MFC编程各个方面的源码」· SHTML 代码 · 共 358 行
SHTML
358 行
<HTML><!-- Header information--><HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <META NAME="Author" CONTENT="Guy Gascoigne - Piggford"> <TITLE>ListView - CSortedListCtrl reusable base class </TITLE></HEAD><!-- Set background properties --><body background="../fancyhome/back.gif" bgcolor="#FFFFFF" link="#B50029" vlink="#8E2323" alink="#FF0000" bgproperties="fixed"><!-- A word from our sponsors... --><table WIDTH="100%"><tr WIDTH="100%"><td><!--#exec cgi="/cgi/ads.cgi"--><td></tr></table><!-- Article Title --><CENTER><H3><FONT COLOR="#AOAO99">CSortedListCtrl reusable base class</FONT></H3></CENTER><CENTER><H3><HR></H3></CENTER><!-- Author and contact details -->This article was contributed by <A HREF="mailto:Christian.Staffe@swn.sni.be">Staffe Christian</A>.<!-- Sample image and source code/demo project --><P>Download the <A HREF="sorted_baseClass.zip">source and example.</A></p><!-- The article... --><p>I found several articles about sorting a CListCtrl, adding visual feedbackin the header... on the codeguru page and I have encapsulated this into areusable base class CSortedListCtrl that encapsulates code from severalother articles. With this class, the user doesn't have to care about allthis sorting stuff, header control, sorting callback... He just has tooverride some virtual routines to implement its sorting algorithm. TheZip file contains a Word 97 DOC for the documentation (<i>ed. which is duplicated here</i>), theSortedListCtrl project encapsulating all the code from previous articles anda project (TestListCtrl) showing how to use the CSortedListCtrl class. It has been compiled with Visual Studio 97.I hope this will be useful to other programmers just like the articles onthe CodeGuru page were for me.<hr><h3>Introduction</h3><p> This is a reusable CSortedListCtrl class based on several articlesfrom the ListView Control section of CodeGuru :<ul> <li>"Indicating sort order in header control - Zafir Anjum" <li>"Sorting the list when user clicks on column header - Zafir Anjum" <li>"Vertical lines for column borders - Zafir Anjum"</ul><h3>How to use the class</h3><p> A compilable test project is available and I will only use someextracts here to explain the code. There is no explanation on the codefrom the other articles, just go there and read them if you areinterested.<p>I have put all the CSortedListCtrl stuff in a separate library file soI can use it from all my projects. To use the class, you need the"SortedListCtrl" project which will produce a library. Insert thisproject into your project (in the sample, I have used a Dialog basedapp called TestListCtrl) that will be using the CSortedListCtrl andset a dependency so it will recompile automatically.<p>CSortedListCtrl acts as a base class like CDialog. So you will need toderive your own class : let's say CMyListCtrl. You can make it usingClass Wizard : you drop a CListCtrl on your dialog box, set it inreport mode and add a class CMyListCtrl setting CListCtrl as a baseclass but you will have to change CListCtrl into CSortedListCtrl inWizard generated code (in .h and message map) You will also need to#include "SortedListCtrl.h", add an additional include directory(the SortedListCtrl directory) in the project settings, define avariable for your list control (m_ListCtrl in the example) and set itstype to CMyListCtrl (not CListCtrl).<p> I use a ListCtrl with two columns and no image. Let's say a columnName of type string and a column Number of type integer to illustratethe sorting routine with two different types. You need to build thelist columns in the OnInitDialog routine. To clearly show the codeadded, this is done in an ExtraInit function called from OnInitDialog:<pre><tt><font COLOR="#990000">void CTestListCtrlDlg::ExtraInit(){ CRect Rect1; m_ListCtrl.GetWindowRect(Rect1); int cx = (Rect1.Width() - 4) >> 1; m_ListCtrl.InsertColumn(0, "Name", LVCFMT_LEFT, cx); m_ListCtrl.InsertColumn(1, "Number", LVCFMT_LEFT, cx); FillList(); // Add full row selection to listctrl m_ListCtrl.SetFullRowSel(TRUE); // Sort the list according to the Name column m_ListCtrl.SortColumn(0, TRUE);}</font></tt></pre><p> SetFullRowSel is a method of CSortedListCtrl that allows to selectthe entire line, not only the first column while the SortColumn methodallows you to sort the list on a given column and choosing ascendingor descending order (sorting mechanism is explained later).<p>Now let's have a look at the FillList routine : <pre><tt><font COLOR="#990000">void CTestListCtrlDlg::FillList(){ CMyItemInfo *pItemInfo; int iItem = 0; CString Name; int Number; Name = "Sharon Stone"; Number = -1; m_ListCtrl.InsertItem(iItem, LPSTR_TEXTCALLBACK); pItemInfo = new CMyItemInfo (iItem, Name, Number); m_ListCtrl.SetItemData(iItem, (DWORD)pItemInfo); m_ListCtrl.SetItemText(iItem, 1, LPSTR_TEXTCALLBACK); iItem++; Name = "Julia Roberts"; Number = 1; m_ListCtrl.InsertItem(iItem, LPSTR_TEXTCALLBACK); pItemInfo = new CMyItemInfo (iItem, Name, Number); m_ListCtrl.SetItemData(iItem, (DWORD)pItemInfo); m_ListCtrl.SetItemText(iItem, 1, LPSTR_TEXTCALLBACK);}</font></tt></pre><p> It just fills the list with two items but won't compile yetbecause it needs another class used by the sorting mechanism. Sortingthe list using the standard mechanism provided by CListCtrl requiresthat you attach some item data to your items because what will begiven to you in the compare routine (see later) will be pointers tothese item data. In order to hide the callback mechanism used byCListCtrl and be able to use polymorphism, the data attached to theitem is encapsulated in a class. I give you a base class CitemInfofrom which you can derive your own class, let's say CMyItemInfo. Youcan do this with class wizard, specifying a generic class derivingpublicly from CItemInfo (ItemInfo.h is provided in the SortedListCtrlproject). You will have to do some #includes with ItemInfo.h andMyItemInfo.h.Now, you can just add some class members, constructor and methods toyour MyItemInfo class to set and retrieve easily information. To makeit easy, I have put everything in the MyItemInfo.h file :<pre><tt><font COLOR="#990000">#include "ItemInfo.h"class CMyItemInfo : public CItemInfo {public: CMyItemInfo(int iItem, CString& Name, int Number) : CItemInfo(iItem), m_Name(Name), m_Number(Number) {m_NumberAsString.Format("%d",Number); }; virtual ~CMyItemInfo() {}; CString& GetName() {return m_Name;} int GetNumber() {return m_Number;} CString& GetNumberAsString() {return m_NumberAsString;}private: CMyItemInfo(); CString m_Name; CString m_NumberAsString; int m_Number;};</font></tt></pre><p>The basic idea for the sort to work is to put the data inside theMyItemInfo class which will be passed to the comparison routine. Inorder not to duplicate data (it's a time/space compromise choicehere), the LPSTR_TEXTCALLBACK is used. To make it work, you must addthe following line in MyListCtrl.h :<pre><tt><font COLOR="#990000">afx_msg void OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult);</font></tt></pre><p>and the following one in the message map of MyListCtrl.cpp : <pre><tt><font COLOR="#990000">ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetDispInfo)</font></tt></pre><p>Then, you have to implement the OnGetDispInfo routine : <pre><tt><font COLOR="#990000">void CMyListCtrl::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; if (pDispInfo->item.mask & LVIF_TEXT) { CMyItemInfo* pAppItem = reinterpret_cast<CMyItemInfo*>(pDispInfo->item.lParam); switch (pDispInfo->item.iSubItem) { case 0 : lstrcpy (pDispInfo->item.pszText, pAppItem->GetName()); break; case 1 : lstrcpy (pDispInfo->item.pszText, pAppItem->GetNumberAsString()); break; } } *pResult = 0;}</font></tt></pre><p>It's not finished yet ! You have to give acorrect constructor for the CMyListCtrl class :<pre><tt><font COLOR="#990000">CMyListCtrl::CMyListCtrl() : CSortedListCtrl(TRUE, TRUE){}</font></tt></pre><p> The first constructor parameter tells the base class if you wantto sort the column (it's normally what you want here !) and the secondparameter informs the base class to handle the deletion of the itemdata itself. In fact, if you remember the code in FillList, weallocate objects of type CMyItemInfo on the heap to attach to the listitems. When elements of the list are deleted, these MyItemInfo must bealso deleted and the base class can do it for you. This is possiblebecause CMyItemInfo derives from ItemInfo and the CItemInfo destructoris virtual.<p> Now, we must still provide a comparison routine : this is done byoverridding a virtual function from CSortedListCtrl that is used tosort the elements in the list. This is just an OO translation of thecallback mechanism used by the standard control that's now hidden inthe base class.<p>Just add the following method declaration in your MyListCtrl.h file : <pre><tt><font COLOR="#990000">int CompareItems(CItemInfo *pItemInfo1, CItemInfo *pItemInfo2);</font></tt></pre><p>and the following definition in the MyListCtrl.cpp file :<pre><tt><font COLOR="#990000">int CMyListCtrl::CompareItems(CItemInfo *pItemInfo1, CItemInfo *pItemInfo2){ CMyItemInfo *pInfo1 = static_cast<CMyItemInfo*>(pItemInfo1); CMyItemInfo *pInfo2 = static_cast<CMyItemInfo*>(pItemInfo2); int nResult; switch (GetSortedColumn()) { case 0 : // Sort on column 'Name' nResult = pInfo1->GetName().CompareNoCase(pInfo2->GetName()); break; case 1 : // Sort on column 'Number' { int Number1 = pInfo1->GetNumber(); int Number2 = pInfo2->GetNumber(); if (Number1 < Number2) { nResult = -1; } else { nResult = (Number1 != Number2); } break; } default : nResult = 0; break; } return IsAscSorted() ? nResult : -nResult;}</font></tt></pre><p> In fact, this function will be called for each pair of item in thelist that must be compared and you receive as parameters, the itemdata attached to each of the element (I will describe below how toattach these ItemInfo to the list items). In this function, you arelikely to use two functions from the base class : GetSortedColumn andIsAscSorted which are telling you respectively the column to be sortedand the sort order (ascending or descending). The return value has thesame semantic as the callback routine from CListCtrl or the strcmpfunctions (-1, 0 or 1). Note also the safe static_cast here becauseCMyItemInfo inherits from CItemInfo.<p>That's all folks !<!-- Remember to update this --><p>Last updated: 6 June 1998<P><HR><!-- Codeguru contact details --><TABLE BORDER=0 WIDTH="100%"><TR><TD WIDTH="33%"><FONT SIZE=-1><A HREF="http://www.codeguru.com">Goto HomePage</A></FONT></TD><TD WIDTH="33%"><CENTER><FONT SIZE=-2>© 1997 Zafir Anjum</FONT> </CENTER></TD><TD WIDTH="34%"><DIV ALIGN=right><FONT SIZE=-1>Contact me: <A HREF="mailto:zafir@home.com">zafir@home.com</A> </FONT></DIV></TD></TR></TABLE></BODY></HTML>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?