四、實踐學習:一個ListCtrl的詳細實現
1.切換到第一個對話框點擊ListCtrl控件
2.在屬性窗口,改變View屬性爲Report
3.創建ListCtrl的列,在OnInitDialog()中添加代碼如下:
BOOL CDeptStore2Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
LVCOLUMN lvColumn;
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_CENTER;
lvColumn.cx =60;
lvColumn.pszText ="Item #";
this->m_StoreItems.InsertColumn(0, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx =100;
lvColumn.pszText ="Category";
this->m_StoreItems.InsertColumn(1, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx =160;
lvColumn.pszText ="Item Name";
this->m_StoreItems.InsertColumn(2, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx =80;
lvColumn.pszText ="Size";
this->m_StoreItems.InsertColumn(3, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_RIGHT;
lvColumn.cx =60;
lvColumn.pszText ="Unit Price";
this->m_StoreItems.InsertColumn(4, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_RIGHT;
lvColumn.cx =30;
lvColumn.pszText ="Qty";
this->m_StoreItems.InsertColumn(5, &lvColumn);
this->m_StoreItems.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
return TRUE; // return TRUE unless you set the focus to a control
}
4.準備創建一個完全的項,設計一個第一個對話框如下:
Control
|
Caption
|
ID
|
Other Properties
|
Static Text
|
Category:
|
|
|
Combo Box
|
|
IDC_CATEGORIES
|
Data: Babies;Teens;Women;Men;Miscellaneous
|
Static Text
|
Item Name:
|
|
|
Edit Control
|
|
IDC_ITEMNAME
|
|
Static Text
|
Item Size:
|
|
|
Edit Control
|
|
IDC_ITEMSIZE
|
|
Static Text
|
Qty:
|
|
|
Edit Control
|
|
IDC_QUANTITY
|
|
Static Text
|
Unit Price:
|
|
|
Edit Control
|
|
IDC_UNITPRICE
|
|
Static Text
|
Item #:
|
|
|
Edit Control
|
|
IDC_ITEMNUMBER
|
|
Button
|
OK
|
IDOK
|
|
Button
|
Cancel
|
IDCANCEL
|
|
5.如下創建CString變量
ID
|
Value Variable
|
IDC_CATEGORIES
|
m_Categories
|
IDC_ITEMNAME
|
m_ItemName
|
IDC_ITEMSIZE
|
m_ItemSize
|
IDC_QUANTITY
|
m_Quantity
|
IDC_UNITPRICE
|
m_UnitPrice
|
6.在主窗口中,雙擊新建項改變它的實現爲:
void CDeptStore2Dlg::OnBnClickedNewitem()
{
// TODO: 在此添加控件通知處理程序代碼
CNewStoreItemDlg1 dlg;
srand( (unsigned)time(NULL) );
wchar_t strNumber[20];
int number1 = rand() %999;
int number2 = rand() %999;
swprintf(strNumber, TEXT("%d-%d"), number1, number2);
dlg.m_ItemNumber = strNumber;
if( dlg.DoModal() )
{
LVITEM lvItem;
int nItem;
lvItem.mask = LVIF_TEXT;
lvItem.iItem =0;
lvItem.iSubItem =0;
lvItem.pszText = strNumber;
nItem =this->m_StoreItems.InsertItem(&lvItem);
this->m_StoreItems.SetItemText(nItem, 1, dlg.m_Categories);
this->m_StoreItems.SetItemText(nItem, 2, dlg.m_ItemName);
this->m_StoreItems.SetItemText(nItem, 3, dlg.m_ItemSize);
this->m_StoreItems.SetItemText(nItem, 4, dlg.m_UnitPrice);
this->m_StoreItems.SetItemText(nItem, 5, dlg.m_Quantity);
}
}
7.運行應用程序,用下面的數據創建數據項(讓計算機隨機生成itemNumber)
Category
|
Item Name
|
Size
|
Qty
|
Unit Price
|
Women
|
Cashmere Lined Glove
|
8
|
12
|
115.95
|
Miscellaneous
|
Chocolate Gift Box
|
Medium
|
5
|
45.00
|
Men
|
Trendy Jacket
|
Medium
|
8
|
45.85
|
Women
|
Stretch Flare Jeans
|
Petite
|
6
|
27.75
|
Women
|
Belted Sweater
|
Large
|
10
|
15.95
|
Teens
|
Girls Classy Handbag
|
One Size
|
4
|
95.95
|
Women
|
Casual Dress Shoes
|
9.5M
|
16
|
45.95
|
Babies
|
Infant Girls Ballerina Dress
|
2M
|
14
|
22.85
|
Teens
|
Girls Velour Dress
|
10
|
8
|
12.55
|
Women
|
Lace Desire Panty
|
M
|
22
|
7.15
|
Teens
|
Boys Hooded Sweatshirt
|
M (7/8)
|
16
|
42.75
|
Men
|
Classic Pinstripe Suit
|
38
|
8
|
145.90
|
8.關閉窗口,返回應用程序
Views轉換
你可以創建一個ListCtrl顯示一個單獨的View,你也可以允許用戶區改變從一個View到另外一個。和剛纔所說的一樣,在設計的時候或者程序動態創建一個ListCtrl,你可以設置一個初始化View用ComboBox去選擇一個View。如果你想在初始化的時候顯示,你可以停到那裏,否則你可以提供改變的一種。
因爲在一個ListCtrl顯示的View是它風格的一部分。爲了動態改變它的View模型,你可以用GetWindowLong()返回控件的風格。GetWindowLong()函數只返回當前控件的風格。你可能需要在改變它之前選擇它。通過爲GetWindowLong()函數增加LVS_TYPEMASK常量,在選擇控件的View之後,你接着可以用SetWindowLong()函數來改變它的風格。示例如下:
void COthersDlg::OnIconBtn()
{
// TODO: Add your control notification handler code here
LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE);
mListStyle &=~LVS_TYPEMASK;
mListStyle |= LVS_ICON;
SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle);
}
void COthersDlg::OnSmallIconBtn()
{
// TODO: Add your control notification handler code here
LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE);
mListStyle &=~LVS_TYPEMASK;
mListStyle |= LVS_SMALLICON;
SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle);
}
void COthersDlg::OnListBtn()
{
// TODO: Add your control notification handler code here
LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE);
mListStyle &=~LVS_TYPEMASK;
mListStyle |= LVS_LIST;
SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle);
}
void COthersDlg::OnReportBtn()
{
// TODO: Add your control notification handler code here
LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE);
mListStyle &=~LVS_TYPEMASK;
mListStyle |= LVS_REPORT;
SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle);
}
五、實踐學習:改變ListCtrl的View
1.在類視圖中,擴展DeptStore2,右擊CDeptStoreDlg2->Add->Add Function
2.設置返回值爲DWORD類型,函數名爲GetViewType
3.點擊完成,函數實現如下:
DWORD CDeptStore2Dlg::GetViewType(void)
{
return (GetStyle() & LVS_TYPEMASK);
}
4.在類視圖中,右擊CDeptStore2Dlg->Add->Add Function
5.設置返回值爲void,函數名稱爲SetViewType,參數類型爲DWORD,參數名爲dwViewType,點擊Add。
6.點擊完成,函數實現如下:
void CDeptStore2Dlg::SetViewType(DWORD dwViewType)
{
DWORD dwCurType;
HWND hWnd;
hWnd =this->m_StoreItems;
GetSafeHwnd();
dwCurType = ::GetWindowLong(hWnd, GWL_STYLE);
dwCurType &=~LVS_TYPEMASK;
dwViewType |= dwCurType;
::SetWindowLong(hWnd, GWL_STYLE, dwViewType);
}
7.切換到第一個對話框,如下增加四個按鈕:
Button ID
|
Caption
|
IDC_LARGE
|
Large
|
IDC_SMALL
|
Small
|
IDC_LIST
|
List
|
IDC_DETAILS
|
Details
|
8.雙擊Large按鈕,如下實現OnBnClicked事件:
void CDeptStore2Dlg::OnBnClickedLarge()
{
// TODO: Add your control notification handler code here
SetViewType(LVS_ICON);
}
9.類似添加其他按鈕的事件響應函數,如下:
void CDeptStore2Dlg::OnBnClickedSmall()
{
// TODO: Add your control notification handler code here
if( GetViewType() != LVS_SMALLICON)
SetViewType(LVS_SMALLICON);
}
void CDeptStore2Dlg::OnBnClickedList()
{
// TODO: Add your control notification handler code here
if( GetViewType() != LVS_LIST)
SetViewType(LVS_LIST);
}
void CDeptStore2Dlg::OnBnClickedDetails()
{
// TODO: Add your control notification handler code here
if( GetViewType() != LVS_REPORT)
SetViewType(LVS_REPORT);
}
10.保存
ListCtrl和Icon
ListCtrl可以將實現圖片,顯示記錄或者將兩者組合顯示。如果你想在列上顯示一幅位圖,你應該聲明一個CImageList變量並初始化。然後調用CListCtrl::SetImageList()方法,併爲之傳參。如果你想這麼做,並且你用的是第一個版本傳遞LVCOLUMN指針參數CListCtrl::InsertColumn()方法,需要給mask參數添加LVCF_IMAGE值,並且爲fmt添加LVCFMT_IMAGE值。指定的圖像會顯示在列的首項上,把列的索引賦給iImage變量。示例如下:
BOOL COthersDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
LVCOLUMN lvColumn;
CImageList *ImgHeaders = new CImageList;
ImgHeaders->Create(16, 16, ILC_MASK, 1, 1);
ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_UP));
ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_LOSANGE));
m_List.SetImageList(ImgHeaders, LVSIL_SMALL);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE;
lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE;
lvColumn.cx = 120;
lvColumn.pszText = "Full Name";
lvColumn.iImage = 0;
m_List.InsertColumn(0, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 100;
lvColumn.pszText = "Profession";
m_List.InsertColumn(1, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE;
lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE;
lvColumn.iImage = 1;
lvColumn.cx = 80;
lvColumn.pszText = "Fav Sport";
m_List.InsertColumn(2, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 75;
lvColumn.pszText = "Hobby";
m_List.InsertColumn(3, &lvColumn);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
在控件上使用位圖或圖標,你應該首先創建位圖或圖。如果你不打算使用Report View並且你想使用位圖,你可以創建一個很長的位圖(由一些小的大小相似的位圖組成)。每一幅圖像供每一個項使用。正常情況下,每個圖片應該大小爲16*16或者更小。下面是示例:
位圖是由6幅相同大小的圖片組成的。如果你不打算使用Report View並且你打算使用icons,那麼就應該單獨的創建16*16大小的icon。
如果你想使用ReportView和其他Views顯示控件項,如果你想使用位圖,你用該創建兩個長位圖。一個應該是16*16大小的。這樣的圖片用來做小圖標(small icon),List,和ReportViews。你應該創建第二個位圖,大小爲32*32。這些圖片用來爲ListView服務。
在你創建完位圖或者圖標之後,緊接着聲明一個指向CImageList類的指針並且用CImageList::Create方法來初始化。調用CListCtrl::SetImageList()方法來確定有效。語法如下:
CImageList* SetImageList(CImageList* pImageList, int nImageList);
pImageList:CImageList變量或者已被初始化的指針。
nImageList:使用ImageList的類型標識,它可以是如下幾個值:
Value
|
Description
|
LVSIL_NORMAL
|
The image list is made of large bitmap or icons, typically 32x32
|
LVSIL_SMALL
|
The image list is made of small bitmap or icons, typically 16x16
|
LVSIL_STATE
|
The image list is made of pictures that will be used as mask
|
你可以使用CListCtrl::InsertItem()的幾個版本來實現,向列表項關聯圖片:
int InsertItem(int nItem, LPCTSTR lpszItem, int nImage );
int InsertItem(UINT nMask,
int nItem,
LPCTSTR lpszItem,
UINT nState,
UINT nStateMask,
int nImage,
LPARAM lParam );
nImage:使用圖片的索引。
nMask:和LVITEM::mask成員類似,它簡單的指定你需要在項上顯示的信息。
nState:和LVITEM::state成員變量相似,指定項的行爲。是否能被選中,失去焦點時,以及有沒有剪切粘貼操作,高亮和拖拽功能。
nStateMask:用來結合nState參數。指定精確的類型信息。
lParam:和TVITEM的lParam成員一樣,用來執行指定項的操作,例如牽涉到項的排序和查找。
六、實踐學習:爲ListCtrl控件項關聯位圖
1.創建位圖,在主菜單,右擊工程->添加資源,在添加資源對話框內選擇位圖->單擊新建
2.在設置屬性窗口中,改變ID爲IDB_SMALLIMG,設置高度爲16,寬度爲144.設計如下位圖:
3.在增加位圖,設置ID爲IDB_LARGING,設置寬度爲32,高度爲288。設計位圖如下:
4.在主對話框的頭文件中聲明兩個CImageList變量,如下:
private:
CImageList m_SmallImg;
CImageList m_LargeImg;
};
5. 在OnInitDialog()方法中添加如下初始化代碼:
m_SmallImg.Create(IDB_SMALLING, 16, 1, RGB(255, 255, 255));
m_LargeImg.Create(IDB_LARGING, 32, 1, RGB(255, 255, 245));
m_StoreItems.SetImageList(&m_SmallImg, LVSIL_SMALL);
m_StoreItems.SetImageList(&m_LargeImg, LVSIL_NORMAL);
6.使用圖像,改變新建的事件響應函數:
void CDeptStore2Dlg::OnBnClickedNewitem()
{
// TODO: 在此添加控件通知處理程序代碼
CNewStoreItemDlg1 dlg;
srand( (unsigned)time(NULL) );
wchar_t strNumber[20];
int number1 = rand() %999;
int number2 = rand() %999;
swprintf(strNumber, TEXT("%d-%d"), number1, number2);
dlg.m_ItemNumber = strNumber;
if( dlg.DoModal() )
{
LVITEM lvItem;
int nItem;
int imgNbr;
if( dlg.m_Categories == TEXT("Babies") )
imgNbr =0;
elseif( dlg.m_Categories == TEXT("Teens") )
imgNbr =1;
elseif( dlg.m_Categories == TEXT("Women") )
imgNbr =2;
elseif( dlg.m_Categories == TEXT("Men") )
imgNbr =3;
else// if( dlg.m_Category == "Miscellaneous" )
imgNbr =4;
lvItem.mask = LVIF_TEXT;
lvItem.iItem =0;
lvItem.iSubItem =0;
lvItem.iImage = imgNbr;
lvItem.pszText = strNumber;
nItem =this->m_StoreItems.InsertItem(&lvItem);
this->m_StoreItems.SetItemText(nItem, 1, dlg.m_Categories);
this->m_StoreItems.SetItemText(nItem, 2, dlg.m_ItemName);
this->m_StoreItems.SetItemText(nItem, 3, dlg.m_ItemSize);
this->m_StoreItems.SetItemText(nItem, 4, dlg.m_UnitPrice);
this->m_StoreItems.SetItemText(nItem, 5, dlg.m_Quantity);
}
}
7.運行程序
<完>