報表式CListCtrl的使用詳解初稿 (轉)
嚴格說來本文是別人成果的集合,加入了本人使用的一點心得,而且文章內容是本人在實際開發中試驗過可以使用的。這只是初稿,還有很多內容沒有加入,原因是沒有經過驗證,以後會陸續加入,形成一個CListCtrl的使用完全指南。
建立圖形列表並和CListCtrl關聯:
m_image_list.Create(I_CALLER2, 16, 10, RGB(192,192, 192));
m_image_list.SetBkColor( GetSylor( COLOR_WINDOW ) );
m_caller_list.SetImageList( &m_image_list, LVSIL_SMALL);
為報表新增4列:
char *szColumn[]={"暱稱","","登陸時間","狀態"};
int widths[]={100,98,70,55};
LV_COLUMN lvc;
lvc.mask=LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;
lvc.fmt=LVCFMT_LEFT;
for(int i=0;i<4;i++) {//插入各列
lvc.pszText=szColumn[i];
lvc.cx=widths[i];
lvc.iSubItem=i;
m_caller_list.InsertColumn(i,&lvc);
}
為報表新增兩項,以附加方式新增:
char* data[4];
data[0]="所有人";
data[1]="0.0.0.0";
data[3]="線上";
data[2]=new char;
CTime now=CTime::GetCurrentTime();
CString temp = now.Format("%H:%M:%S");
data[2]=temp.GetBuffer(1);
LV_ITEM lvi;
lvi.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
lvi.iSubItem=0;
lvi.pszText=(char *)data[0];
lvi.iImage = 0;
lvi.iItem=0;
m_caller_list.InsertItem(&lvi);
for (int j=0;j<4;j++) m_caller_list.SetItemText(count,j,data[j]);
count++;
lvi.iImage = 1;
lvi.iItem=count;
m_caller_list.InsertItem(&lvi);
data[0]="cherami";
data[1]="127.0.0.1";
for (int n=0;n<4;n++) m_caller_list.SetItemText(count,n,data[n]);
count++;
設定報表的樣式
選中一整行:
m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_FULLROW);
繪製表格:
m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_GRIDLINES);
帶核取方塊:
m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_CHECKBOXES);
自動切換:
m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_TRACKSELECT);
選定一行:
設定CListCtrl的Show selection always選項
SetItemState (iIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED)
選中一個或多個專案時,會傳送LVN_ITEMCHANGED訊息,可以使用
GetSelectedCount()方法得到被選定的項的數目。
點選列頭的訊息響應:
ON_NOTIFY(HDN_ITEMCLICKW, 0, ResponseFunc)
訊息,需要自己新增
或者:
ON_NOTIFY(LVN_COLUMNCLICK, ID_yourCtrl, ResponseFunc)//嚮導新增
前者後響應,後者先響應
響應:
ResponseFunc(NMHDR *pNMHDR, LRESULT *pResult)
雙擊CListCtrl中的ITEM的訊息是及訊息函式:
ON_NOTIFY(NM_DBLCLK, ID_yourCtrl, ResponseFunc)
單擊ITEM的訊息響應:
ON_NOTIFY(NM_CLICK, ID_yourCtrl, ResponseFunc)
ResponseFunc(NMHDR *pNMHDR, LRESULT *pResult)
HDN_ITEMCLICK 就是Header control Notify message for mouse left click on the Header control!
而HDN_ITEMCLICK是當List View中存在一個Header Contrl時,Header Ctrl通知父視窗List View的!
CListCtrl中的Item被選中觸發LBN_SELCHANGE(透過WM_COMMAND)訊息!
刪除CListCtrl中選定的項:
POSITION pos;
int nIndex;
for(; pos= GetFirstSelectedItemPosition();)
{
nIndex = GetNextSelectedItem(pos);
DeleteItem(nIndex);
}
在ListCtrl中進行排序
列表(CListCtrl)的頂部有一排按鈕,可以透過選擇不同的列來對記錄進行排序。但是 CListCtrl並沒有自動排序的功能,我們需要自己新增一個用於排序的回撥函式來比較兩個資料的大小,此外還需要響應排序按鈕被點選的訊息。下面講述一下具體的做法。
CListCtrl提供了用於排序的函式,函式原型為:BOOL CListCtrl::SortItems( PFNLVCOMPARE pfnCompare, D dwData )。其中第一個引數為全域性排序函式的地址,第二個引數為使用者資料,你可以根據你的需要傳遞一個資料或是指標。該函式返回-1代表第一項排應在第二項前面,返回1代表第一項排應在第二項後面,返回0代表兩項相等。
用於排序的函式原形為:int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort),其中第三個引數為者傳遞的資料(即呼叫SortItems時的第二個引數dwData)。第一和第二個引數為用於比較的兩項的ItemData,你可以透過DWORD CListCtrl::GetItemData( int nItem )/BOOL CListCtrl::SetItemData( int nItem, DWORD dwData )來對每一項的ItemData進行存取。在新增項時選用特定的CListCtrl::InsertItem也可以設定該值。由於你在排序時只能透過該值來確定項的位置所以你應該比較明確的確定該值的含義。
最後一點,我們需要知道什麼時候需要排序,實現這點可以在父視窗中對LVN_COLUMNCLICK訊息進行處理來實現。
下面我們看一個例子,這個例子是一個派生類,並支援順序/倒序兩種方式排序。為了簡單我對全域性資料進行排序,而在實際應用中會有多組需要排序的資料,所以需要透過傳遞引數的方式來告訴派序函式需要對什麼資料進行排序。
//全域性資料
struct DEMO_DATA
{
char szName[20];
int iAge;
}strAllData[5]={{"王某",30},{"張某",40},{"武某",32},{"陳某",20},{"李某",36}};
//CListCtrl派生類定義
class CSortList : public CListCtrl
{
// Construction
public:
CSortList();
BOOL m_fAsc;//是否順序排序
int m_nSortedCol;//當前排序的列
protected:
//{{AFX_MSG(CSortList)
//}}AFX_MSG
...
};
//父視窗中包含該CListCtrl派生類
class CSort_in_list_ctrlDlg : public CDialog
{
// Construction
public:
CSort_in_list_ctrlDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CSort_in_list_ctrlDlg)
enum { IDD = IDD_SORT_IN_LIST_CTRL_DIALOG };
CSortList m_listTest;
//}}AFX_DATA
}
//在父視窗中定義LVN_COLUMNCLICK訊息對映
BEGIN_MESSAGE_MAP(CSort_in_list_ctrlDlg, CDialog)
//{{AFX_MSG_MAP(CSort_in_list_ctrlDlg)
ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnColumnclickList1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//初始化資料
BOOL CSort_in_list_ctrlDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//初始化ListCtrl中資料列表
m_listTest.InsertColumn(0,"姓名");
m_listTest.InsertColumn(1,"年齡");
m_listTest.SetColumnWidth(0,80);
m_listTest.SetColumnWidth(1,80);
for(int i=0;i<5;i++)
{
m_listTest.InsertItem(i,strAllData[i].szName);
char szAge[10];
sprintf(szAge,"%d",strAllData[i].iAge);
m_listTest.SetItemText(i,1,szAge);
//設定每項的ItemData為陣列中資料的
//在排序函式中透過該ItemData來確定資料
m_listTest.SetItemData(i,i);
}
return TRUE; // return TRUE unless you set the focus to a control
}
//處理訊息
void CSort_in_list_ctrlDlg::OnColumnclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
//設定排序方式
if( pNMListView->iSubItem == m_listTest.m_nSortedCol )
m_listTest.m_fAsc = !m_listTest.m_fAsc;
else
{
m_listTest.m_fAsc = TRUE;
m_listTest.m_nSortedCol = pNMListView->iSubItem;
}
//呼叫排序函式
m_listTest.SortItems( ListCompare, (DWORD)&m_listTest );
*pResult = 0;
}
//排序函式實現
int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
//透過傳遞的引數來得到CSortList物件指標,從而得到排序方式
CSortList* pV=(CSortList*)lParamSort;
//透過ItemData來確定資料
DEMO_DATA* pInfo1=strAllData+lParam1;
DEMO_DATA* pInfo2=strAllData+lParam2;
CString szComp1,szComp2;
int iCompRes;
switch(pV->m_nSortedCol)
{
case(0):
//以第一列為根據排序
szComp1=pInfo1->szName;
szComp2=pInfo2->szName;
iCompRes=szComp1.Compare(szComp2);
break;
case(1):
//以第二列為根據排序
if(pInfo1->iAge == pInfo2->iAge)
iCompRes = 0;
else
iCompRes=(pInfo1->iAge < pInfo2->iAge)?-1:1;
break;
default:
ASSERT(0);
break;
}
//根據當前的排序方式進行調整
if(pV->m_fAsc)
return iCompRes;
else
return iCompRes*-1;
}
排序最快:
CListCtrl::SortItems
Example
// Sort the item in reverse alphabetical order.
static int CALLBACK
MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// lParamSort contains a pointer to the list view control.
// The lParam of an item is just its index.
CListCtrl* pListCtrl = (CListCtrl*) lParamSort;
CString strItem1 = pListCtrl->GetItemText(lParam1, 0);
CString strItem2 = pListCtrl->GetItemText(lParam2, 0);
return strcmp(strItem2, strItem1);
}
void snip_CListCtrl_SortItems()
{
// The pointer to my list view control.
extern CListCtrl* pmyListCtrl;
// Sort the list view items using my callback procedure.
pmyListCtrl->SortItems(MyCompareProc, (LPARAM) pmyListCtrl);
}
If you don’t want to allow the users to sort the list by clicking on the header, you can use the style LVS_NOSORTHEADER. However, if you do want to allow sorting, you do not specify the LVS_NOSORTHEADER. The control, though, does not sort the items. You have to handle the HDN_ITEMCLICK notification from the header control and process it appropriately. In the code below, we have used the sorting function SortTextItems() developed in a previous section. You may choose to sort the items in a different manner.
Step 1: Add two member variables
Add two member variables to the CListCtrl. The first variable to track which column has been sorted on, if any. The second variable to track if the sort is ascending or descending.
int nSortedCol;
BOOL bSortAscending;
Step 2: Initialize them in the constructor.
Initialize nSortedCol to -1 to indicate that no column has been sorted on. If the list is initially sorted, then this variable should reflect that.
nSortedCol = -1;
bSortAscending = TRUE;
Step 3: Add entry in message map to handle HDN_ITEMCLICK
Actually you need to add two entries. For HDN_ITEMCLICKA and HDN_ITEMCLICKW. Do not use the class wizard to add the entry. For one, you need to add two entries whereas the class wizard will allow you only one. Secondly, the class wizard uses the wrong macro in the entry. It uses ON_NOTIFY_REFLECT() instead of ON_NOTIFY(). Since the HDN_ITEMCLICK is a notification from the header control to the list view control, it is a direct notification and not a reflected one.
ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHeaderClicked)
ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHeaderClicked)
Note that we specify the same function for both the notification. Actually the program will receive one or the other and not both. What notification it receives will depend on the OS. The list view control on 95 will send the ANSI version and the control on NT will send the UNICODE version.
Also, note that the second argument is zero. This value filters for the id of the control and we know that header control id is zero.
Step 4: Write the OnHeaderClicked() function
Here’s where you dec what to do when the user clicks on a column header. The expected behaviour is to sort the list based on the values of the items in that column. In this function we have used the SortTextItems() function developed in a previous section. If any of the columns displays numeric or date values, then you would have to provide custom sorting for them.
void CMyListCtrl::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
if( phdn->iButton == 0 )
{
// User clicked on header using left mouse button
if( phdn->iItem == nSortedCol )
bSortAscending = !bSortAscending;
else
bSortAscending = TRUE;
nSortedCol = phdn->iItem;
SortTextItems( nSortedCol, bSortAscending );
}
*pResult = 0;
}
讓CListCtrl的SubItem也具有編輯功能:
要過載一個文字框,然後在LVN_BEGINLABELEDIT時改變文字框位置。
CInEdit m_InEdit;
if( ( GetStyle() & LVS_TYPEMASK ) == LVS_REPORT && ( m_nEditSubItem != 0 ) )
{
HWND hwndEdit;
CRect rtBound;
CString strText;
hwndEdit = (HWND)SendMessage( LVM_GETEDITCONTROL );
GetSubItemRect( pDispInfo->item.iItem, m_nEditSubItem, LVIR_LABEL, rtBound );
m_InEdit.SubclassWindow( hwndEdit );
m_InEdit.m_left = rtBound.left;
strText = GetItemText( pDispInfo->item.iItem, m_nEditSubItem );
m_InEdit.SetWindowText( strText );
}
void CInEdit::OnWindowPosChanging(WINDOWPFAR* lpwndpos)
{
CRect rtClient;
lpwndpos->x = m_left; // m_left在LVN_BEGINLABELEDIT中設定
CEdit::OnWindowPosChanging(lpwndpos);
// TODO: Add your message handler code here
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990821/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 正規表示式使用詳解(轉)
- DELPHI中使用API函式詳解 (轉)API函式
- 硬碟分割槽表詳解(轉)硬碟
- eval使用詳解(轉)
- Statspack分析報告詳解(轉)
- linux的umask函式詳解(轉)Linux函式
- oracle over函式 詳解(轉)Oracle函式
- CListCtrl控制元件樣式設定時出現的小插曲!控制元件
- oracle外部表詳解以及使用Oracle
- 【轉】非同步的AsyncHttpClient使用詳解非同步HTTPclient
- pexpect庫run函式的使用詳解函式
- 詳解Javascript中正規表示式的使用JavaScript
- Oracle Profile 使用詳解(轉)Oracle
- passwd 命令使用詳解(轉)
- chattr 命令使用詳解(轉)
- mv命令使用詳解(轉)
- su命令使用詳解(轉)
- Java開源報表JasperReport、iReport4.5.1使用詳解(一)Java
- setdefaultencoding函式使用詳解Encoding函式
- 分散式儲存glusterfs詳解【轉】分散式
- AdapterView的使用與getView函式詳解APTView函式
- find和xargs使用詳解(轉)
- ind和xargs使用詳解(轉)
- setjmp 和 longjmp 函式使用詳解函式
- JS正規表示式使用詳解JS
- PHP閉包函式使用詳解PHP函式
- C++ Lambda 表示式使用詳解C++
- Spring EL表示式使用詳解Spring
- SAP ABAP報表依賴設計原理詳解
- ActiveReports 報表應用教程 (10)---互動式報表之向下鑽取(詳細資料按需顯示解決方案)
- MySQL 分割槽表原理及使用詳解MySql
- ORACLE正規表示式函式詳解--轉載整理Oracle函式
- 專案經理技能評估-初稿(轉載)
- 詳解MySQL中的SQRT函式的使用方法MySql函式
- Linux下使用aMsn詳解(轉)Linux
- PL/SQL單行函式和組函式詳解(轉)SQL函式
- Squid-Linux下的使用詳解(轉)UILinux
- 翻譯 | 玩轉 React 表單 —— 受控元件詳解React元件