(四)列表控制的應用技巧示例
本文給出具體實例演示列表控制及前面的表頭控制和圖像列表的應用技巧。步驟如下:
1、通過“FILE->NEW->PROJECTS->MFC AppWizard(EXE)”建立名為VCLIST的工程,在建立過程中選擇基于對話框(Dialog based)的應用;將對話框中的默認控件刪除,并將所有對話框屬性中的Language域設置為Chinese(P.R.C.),以使應用程序支持中文;
建立兩個圖標IDI_GJ和IDI_XS,用來表示圖標的選中和非選中狀態,對于每個圖標都應建立32X32和16X16兩種大小,以保證程序的需要;
3、在對話框窗口中設計組合框(Group Box),組合框中設置四個無線按鈕(Radio)“大圖標|小圖標|列表|資料”,同時設置排序、刪除和關閉三個控制按鈕(Button),并在對話框中設置大小合適的列表控制(List Ctrl),其對應標識分別如下:
--------------------------------------------------------------------------------
控制名稱 標題名稱 標識符號
--------------------------------------------------------------------------------
列表控制 IDC_LISTCTRL
組合框 方式 IDC_STATIC
無線按鈕 大圖標 IDC_STDICON
小圖標 IDC_SMLICON
列 表 IDC_LIST
資 料 IDC_REPORT
按鈕 排 序 IDC_SORT
刪 除 IDC_DEL
關 閉 IDOK
--------------------------------------------------------------------------------
4、在設置無線按鈕時,需要注意的是只有大圖標的Group屬性為選中狀態,而其它無線按鈕的狀態均為默認值。
5、選中列表控制控件,選擇“VIEW->ClassWizard->Memory Variables”,并利用IDC_ LISTCTRL引入成員變量,其變量類型為:
變量名 種類 變量類型
m_ListCtrl Control ClistCtrl
同時利用“MESSAGES MAP”為各無線按鈕和命令按鈕增加控制功能。
6、然后在包含文件和代碼文件中分別加入如下代碼:
(1)在VCLISTDlg.h中增加數據結構和定義
(2)在VCLISTDlg.CPP中的起始處增加初始化數據和程序定義
//在文件開始處增加數據結構初始化

 SPS Sps[]= {//信息

  {"紅梅",0,"1000","30","30000"},

  {"黃梅",0,"1000","29","29000"},

  {"綠梅",0,"1000","28","28000"},

  {"青梅",0,"1000","27","27000"},

  {"白梅",0,"1000","31","31000"},

  {"紅梅",1,"1000","30","30000"},

  {"黃梅",1,"1000","29","29000"},

  {"綠梅",1,"1000","28","28000"},

  {"青梅",1,"1000","27","27000"},

  {"白梅",1,"1000","31","31000"}};

CImageList Cil1,Cil2;//大小圖像列表
 |
(3)在程序初始化處增加表頭、圖像和列表控制建立代碼


BOOL CVCLISTDlg::OnInitDialog()



{CDialog::OnInitDialog();

//
//其它代碼

// TODO: Add extra initialization here此處增加代碼

LV_ITEM lvitem;

LV_COLUMN lvcol;

int i,iPos,iItemNum;

CVCLISTApp *pApp=(CVCLISTApp *)AfxGetApp();//創建圖象列表

Cil1.Create(32,32,TRUE,2,2);

Cil1.Add(pApp->LoadIcon(IDI_GJ));

Cil1.Add(pApp->LoadIcon(IDI_XS));

Cil2.Create(16,16,TRUE,2,2);

Cil2.Add(pApp->LoadIcon(IDI_GJ));

Cil2.Add(pApp->LoadIcon(IDI_XS));//設置圖象列表

m_ListCtrl.SetImageList(&Cil1,LVSIL_NORMAL);

m_ListCtrl.SetImageList(&Cil2,LVSIL_SMALL);//向列表控制中添加表列

lvcol.mask=LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH;

lvcol.fmt=LVCFMT_CENTER;//居中

i=0;

lvcol.pszText="品 名";

lvcol.iSubItem=i;

lvcol.cx=70;

m_ListCtrl.InsertColumn(i++,&lvcol);

lvcol.pszText="數 量";

lvcol.iSubItem=i;

lvcol.cx=70;

m_ListCtrl.InsertColumn(i++,&lvcol);

lvcol.pszText="單 價";

lvcol.iSubItem=i;

lvcol.cx=70;

m_ListCtrl.InsertColumn(i++,&lvcol);

lvcol.pszText="金 額";

lvcol.iSubItem=i;

lvcol.cx=70;

m_ListCtrl.InsertColumn(i++,&lvcol);

//向列表控制中添加表項

iItemNum=sizeof(Sps)/sizeof(SPS);


for(i=0;i<iItemNum;i++)
{

lvitem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;

lvitem.iItem=i;

lvitem.iSubItem=0;

lvitem.pszText=Sps[i].szPm;

lvitem.iImage=Sps[i].Lx;

lvitem.lParam=i;

iPos=m_ListCtrl.InsertItem(&lvitem);//返回表項插入后的索引號

lvitem.mask=LVIF_TEXT;

lvitem.iItem=iPos;

lvitem.iSubItem=1;

lvitem.pszText=Sps[i].szSl;

m_ListCtrl.SetItem(&lvitem);

lvitem.iSubItem=2;

lvitem.pszText=Sps[i].szDj;

m_ListCtrl.SetItem(&lvitem);

lvitem.iSubItem=3;

lvitem.pszText=Sps[i].szJe;

m_ListCtrl.SetItem(&lvitem);

}

CheckRadioButton(IDC_STDICON,IDC_REPORT,IDC_STDICON);

return TRUE; // return TRUE unless you set the focus to a control

}

(4)完善列表顯示方式代碼
在利用Classwizard類向導創建各功能按鈕顯示功能函數之后,必須依次完善這些功能函數的代碼,這些功能函數如下:


void CVCLISTDlg::OnStdicon()//設置大圖標顯示方式



{ // TODO: Add your control notification handler code here

LONG lStyle;

lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型

lStyle&=~LVS_TYPEMASK; //清除顯示方式位

lStyle|=LVS_ICON; //設置顯示方式

SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型

}

void CVCLISTDlg::OnSmlicon() //設置小圖標顯示方式



{ // TODO: Add your control notification handler code here

LONG lStyle;

lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型

lStyle&=~LVS_TYPEMASK; //清除顯示方式位

lStyle|=LVS_SMALLICON; //設置顯示方式

SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型

}

void CVCLISTDlg::OnList() //設置列表顯示方式



{ // TODO: Add your control notification handler code here

LONG lStyle;

lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型

lStyle&=~LVS_TYPEMASK; //清除顯示方式位

lStyle|=LVS_LIST; //設置顯示方式

SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型

}

void CVCLISTDlg::OnReport() //詳細資料顯示方式



{ // TODO: Add your control notification handler code here

LONG lStyle;

lStyle=GetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE);//獲取當前窗口類型

lStyle&=~LVS_TYPEMASK; //清除顯示方式位

lStyle|=LVS_REPORT; //設置顯示方式

SetWindowLong(m_ListCtrl.m_hWnd,GWL_STYLE,lStyle);//設置窗口類型

}


(5)刪除功能的實現
要實現刪除功能,必須取得選中表項的數和表項總數,并且需要從后向前進行依次刪除,其原因是每個表項被刪除后,其后各表項的索引號均會發生遞減變化,如果采取從前向后刪除的方法,就會造成無法正常刪除選中的表項,其功能代碼如下:


void CVCLISTDlg::OnDel() //刪除按鈕功能



{ // TODO: Add your control notification handler code here

int i,iState;

int nItemSelected=m_ListCtrl.GetSelectedCount();//所選表項數

int nItemCount=m_ListCtrl.GetItemCount();//表項總數

if(nItemSelected<1) return;


for(i=nItemCount-1;i>=0;i--)
{

iState=m_ListCtrl.GetItemState(i,LVIS_SELECTED);

if(iState!=0) m_ListCtrl.DeleteItem(i);

}

}


(6)排序功能的實現
列表控制有一個特殊的功能,當以詳細資料方式顯示時,列表頂部的表頭可以當作按鈕來使用,這可以通過列表控制創建時的風格來控制。當鼠標點擊列表頭名稱時,列表控制就會向其父窗口發送一個LNV_COLUMNCLICK消息,利用類導向中列表控制IDC_LISTCTRL對應的LNV_COLUMNCLICK消息加入相應處理函數,就可將表列按照特定順序進行排列。其函數使用方法見程序,其中iSort為排序的表列索引號,(PFNLVCOMPARE)CompareFunc為進行具體排序的回調函數,也就是說,通過鼠標點擊表頭實現的排序過程是由第三方開發的專用排序函數來實現的,排序函數只是實現表項的具體比較操作,而整個排序過程是由SortItemS屬性通過不斷調用這個函數來實現的。正常的排序過程是升序方式,通過調換排序函數中的參數值,就可實現降序排列,即將PARAM1與PARAM2調換位置。這個回調函數的前兩個參數為表列中表項的索引號,第三個參數為排序的表列索引號。


void CVCLISTDlg::OnColumnclickListctrl(NMHDR* pNMHDR, LRESULT* pResult)



{ //鼠標左鍵單擊表頭處理函數

NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

// TODO: Add your control notification handler code here

static int iSorted=-1;//排列序號

if (pNMListView->iSubItem==iSorted) return;

iSorted=pNMListView->iSubItem;

m_ListCtrl.SortItems((PFNLVCOMPARE)CompareFunc,iSorted);

*pResult = 0;

}

//排序時比較表項的回調函數

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort)



{ char *text1,*text2;


switch (lParamSort)
{

case 0L:text1=Sps[lParam1].szPm;

text2=Sps[lParam2].szPm;break;

case 1L:text1=Sps[lParam1].szSl;

text2=Sps[lParam2].szSl;break;

case 2L:text1=Sps[lParam1].szDj;

text2=Sps[lParam2].szDj;break;

case 3L:text1=Sps[lParam1].szJe;

text2=Sps[lParam2].szJe;break;

}

return (strcmp(text1,text2));//結果為>0 =0 <0

}


同樣,也可以通過專用按鈕來實現排序功能,如本文的排序按鈕對應的功能代碼如下:


void CVCLISTDlg::OnSort()



{ // TODO: Add your control notification handler code here

m_ListCtrl.SortItems((PFNLVCOMPARE)CompareFunc,0);}


7、列表視的演練技巧
在使用列表視時,其方法與列表控制基本相同,只不過列表視是在窗口中來實現的而列表控制是在對話框中實現,列表視的各種功能是通過菜單來實現的而列表控制是通過按鈕等方式來實現的,列表控制需要在對話框中創建列表控制控件而列表視直接占據整個窗口,在設計過程中只要將按鈕和列表控制設計過程變為菜單設計,并注意在功能增加是在類向導中是通過菜單命令來操作,同時在每個功能函數前面增加取得列表視引用的命令( CListCtrl& ListCtrl = GetListCtrl()),而其余數據結構和代碼均不需要修改,實現起來比較容易。