表格是我们常用的管理数据控件之一, Win32的标准表格控件默认只显示文本数据,如何在单元格里显示图片? 如何显示复选框,可以够选整行?
表格是的特点是带分割线,以列和行显示数据的控件,我们是否可以通过响应WM_PAINT
消息来全部绘制?为什么说响应
WM_PAINT
消息绘制表格不容易实现?
表格的表头能加上一个复选框的按钮吗? 这样可以实现全选的功能.
WTL封装了Win32的ListView的类叫CListViewCtrl
, 所以我们需要增加额外的图片绘制或功能需要继承CListViewCtrl
, 并且如果需要定制某行某列的内容,需要在在创建CListViewCtrl
增加LVS_REPORT|LVS_OWNERDRAWFIXED
两种样式. 这样才会响应WM_DRAWITEM
消息.
如果要自己从头绘制整个表格,会比较复杂,特别拉动表格头改变列宽时,或者有滚动条时的处理会很麻烦, 还有点击行时显示选中效果,判断是第几行等都不是一个小的工作量。所以一般不会考虑重新实现WM_PAINT
.
表格头要加一个复选框的图片并且还能响应点击效果,一种是方案是在表格头上加一个复选框的按钮,另一种方案就是在表格头上绘制复选框图片,并通过响应WM_LBUTTONDOWN
消息来处理点击复选框图片切换图片达到效果.
我们自定义的子类需要继承COwnerDraw
来绘制单元格, 这个类会在WM_DRAWITEM
的处理函数OnDrawItem
里调用
DrawItem((LPDRAWITEMSTRUCT)lParam)
, 所以我们子类需要重载这个函数。在这个函数里我们能判断该单元格是否选中,是否需要绘制图片等,这个单元格里有我们想知道的所有属性LPDRAWITEMSTRUCT
.
void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
至于表格头,我们也需要通过继承类CHeaderCtrl
,并且继承CCustomDraw
来实现自定义绘制. 由于如果只需要在原来的表格头上加东西,所以只需要重载CCustomDraw
的函数OnPostPaint
和OnPrePaint
,而在
OnPrePaint
里需要返回CDRF_NOTIFYPOSTPAINT
,OnPostPaint
方法才会调用.
由于WTL
其实就是对Win32
的薄封装, CListViewCtrl
在MFC
也有对应的CListView
, 还有就是消息映射也是大同小异, 所以移植到MFC
也容易. 同理,MFC
的自定义控件移植到WTL
也可行.
#ifndef __BAS_LIST_VIEW_HEADER
#define __BAS_LIST_VIEW_HEADER
#include
#include
#include
#include "atlframe.h"
#include "atlctrls.h"
#include "atlmisc.h"
#include
enum HeaderMessage
{
AA_LISTVIEW_HEADER_CHG = WM_USER+1000
};
enum
{
kBASListHeaderCheckButtonId = 5000
};
class BASListViewHeader:public CWindowImpl<BASListViewHeader,CHeaderCtrl>,public CCustomDraw<BASListViewHeader>
{
public:
BASListViewHeader();
~BASListViewHeader();
BEGIN_MSG_MAP(BASListViewHeader)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
CHAIN_MSG_MAP_ALT(CCustomDraw<BASListViewHeader>,1)
END_MSG_MAP()
void SetCheckAll(int bcheck);
BOOL GetIfChecked();
void SetCheckBoxImage(Gdiplus::Bitmap* m_checkbox_yes,
Gdiplus::Bitmap* m_checkbox_no);
void RefreshCheckRect();
DWORD OnPostPaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw);
DWORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw);
protected:
LRESULT OnLButtonDown(UINT umsg,WPARAM wparam,LPARAM lparam,BOOL& bHandled );
private:
Gdiplus::Bitmap* m_checkbox_yes_;
Gdiplus::Bitmap* m_checkbox_no_;
bool checked_;
DWORD bkg_color_;
int m_nHeadHight;
int m_nSortColumn;
BOOL m_bAscend;
int m_iSpacing;
BOOL m_bDividerLines;
};
#endif
#include "stdafx.h"
#include "bas_list_view_header.h"
#include
#include
#include
#include "utils.h"
BASListViewHeader::BASListViewHeader():
m_nHeadHight(25)
,m_nSortColumn(-1)
{
bkg_color_ = RGB(242,242,242);
checked_ = false;
m_checkbox_yes_ = NULL;
m_checkbox_no_ = NULL;
}
BASListViewHeader::~BASListViewHeader()
{
Detach();
}
void BASListViewHeader::SetCheckBoxImage(Gdiplus::Bitmap* m_checkbox_yes,
Gdiplus::Bitmap* m_checkbox_no)
{
m_checkbox_yes_ = m_checkbox_yes;
m_checkbox_no_ = m_checkbox_no;
}
void BASListViewHeader::RefreshCheckRect()
{
CRect rect_client;
GetClientRect(&rect_client);
assert(m_checkbox_yes_);
CRect rect;
rect.left = 0;
rect.top = 0;
rect.right = rect.left+m_checkbox_yes_->GetWidth()+4;
rect.bottom = rect_client.bottom;
InvalidateRect(rect,0);
}
LRESULT BASListViewHeader::OnLButtonDown(UINT umsg,WPARAM wparam,LPARAM lparam,BOOL& bHandled )
{
if(!m_checkbox_yes_)
{
return 0;
}
POINT pt={LOWORD(lparam),HIWORD(lparam)};
HDHITTESTINFO hdht;
hdht.pt=pt;
int nItem=HitTest(&hdht);
if (nItem!=-1 && (hdht.flags & HHT_ONHEADER) && !(hdht.flags & HHT_ONDIVIDER) )
{
//5: 是checkbox的x位置,时间关系暂时先固定.
if( 5 <= pt.x && pt.x <= 5+m_checkbox_yes_->GetWidth())
{
CWindow parent = GetParent();
checked_ = !checked_;
parent.SendMessage(AA_LISTVIEW_HEADER_CHG,checked_,0);
}
}
bHandled = FALSE;
//增加判断识别点击了CheckBox坐标.
return 0;
}
DWORD BASListViewHeader::OnPostPaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw)
{
Gdiplus::Graphics graphics(lpNMCustomDraw->hdc);
if(m_checkbox_yes_){
if(checked_){
Utils::DrawImage(graphics,m_checkbox_yes_,5,4);
}else{
Utils::DrawImage(graphics,m_checkbox_no_,5,4);
}
}
return CDRF_DODEFAULT;
}
DWORD BASListViewHeader::OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCustomDraw)
{
return CDRF_NOTIFYPOSTPAINT;
}
void BASListViewHeader::SetCheckAll(int bcheck)
{
checked_ = bcheck;
}
BOOL BASListViewHeader::GetIfChecked()
{
return checked_;
}
#ifndef __BAS_LIST_VIEW
#define __BAS_LIST_VIEW
#include
#include
#include
#include
#include
#include "atlframe.h"
#include "atlctrls.h"
#include "atlmisc.h"
#include "atlcrack.h"
#include
#include
#include "bas_list_view_header.h"
enum ListViewMessage
{
AA_LISTVIEWCHECKCHG = AA_LISTVIEW_HEADER_CHG+1
};
class BASListView;
typedef CWindowImpl<BASListView,CListViewCtrl> BASListViewBase;
typedef Gdiplus::Image* (*GetLogoImage)(BASListView *list_view,int nItem);
typedef void (*RenderItem)(CDC& hdcmem,BASListView *list_view,int nItem);
typedef enum BASListSeqOrder1
{
BASListSeqOrderAscend,
BASListSeqOrderDescend
}BASListSeqOrder;
class BASListView:public BASListViewBase,public COwnerDraw<BASListView>
{
public:
BASListView();
~BASListView();
BEGIN_MSG_MAP(BASListView)
MSG_WM_ERASEBKGND(OnEraseBkgnd)
MESSAGE_HANDLER(WM_LBUTTONDOWN,OnLButtonDown)
MESSAGE_HANDLER(AA_LISTVIEW_HEADER_CHG,OnListViewHeaderCheck)
MESSAGE_HANDLER(WM_CREATE,OnCreate)
MESSAGE_HANDLER(WM_MOUSEMOVE,OnMouseMove)
CHAIN_MSG_MAP_ALT(COwnerDraw<BASListView>,1)
END_MSG_MAP()
BOOL CreateListView(HWND hWndParent, ATL::_U_RECT rect = NULL,
ATL::_U_MENUorID MenuOrID = 0U,
BASListSeqOrder order = BASListSeqOrderAscend,
bool paint_cross_bg_color = false,bool visible = true);
int InsertItemTexts(int index,...);
int AppendItemTexts(LPCTSTR pszText,...);
void SetItemHeight(int nh);
void SetCheckBoxImage(Gdiplus::Bitmap* m_checkbox_yes,Gdiplus::Bitmap* m_checkbox_no);
static int CALLBACK CompareFunc(LPARAM lparam1,LPARAM lparam2,LPARAM lparamSort);
void SetDefaultPhoto(Gdiplus::Image* m_default_photo);
inline void SetPhotoGetFunc(GetLogoImage func)
{
photo_func_ = func;
}
inline void SetRenderFunc(RenderItem func)
{
render_func_ = func;
}
void SetHeaderCheck(int bcheck)
{
m_listHead.SetCheckAll(bcheck);
}
BOOL GetHeaderChecked()
{
return m_listHead.GetIfChecked();
}
void RefreshHeaderCheck();
void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
void RemoveItem(int nItem)
{
CListViewCtrl::DeleteItem(nItem);
}
void DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct)
{
}
LRESULT CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
{
return 1;
}
void RefreshColumn(int nCol);
void RefreshCell(int nCol,int nRow);
void SetSelectedChecked();
BOOL SelectItem(int nIndex);
protected:
LRESULT OnListViewHeaderCheck(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMouseWheel(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
LRESULT OnVScroll(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
LRESULT OnNcCalSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
ShowScrollBar(SB_BOTH,0);
bHandled=FALSE;
return 0;
}
LRESULT OnLvnColClick(int iID,LPNMHDR pNMListView,BOOL& bHandled);
LRESULT OnCreate(UINT umsg,WPARAM wparam,LPARAM lparam,BOOL& bHandled );
BOOL OnEraseBkgnd(CDCHandle dc);
virtual void DrawPhotoColumn(HDC hdcmem,Gdiplus::Graphics& graphics,
LPDRAWITEMSTRUCT lpDrawItemStruct,CRect& rctext,
int nCol);
virtual void DrawEveryColumnItem(HDC hdcmem,Gdiplus::Graphics& graphics,
LPDRAWITEMSTRUCT lpDrawItemStruc);
Gdiplus::Bitmap* m_checkbox_yes_;
Gdiplus::Bitmap* m_checkbox_no_;
GetLogoImage photo_func_;
RenderItem render_func_;
Gdiplus::Image* m_default_photo_;
COLORREF m_crEven,m_crOdd;
int m_h_offset,m_h_size;
private:
BASListViewHeader m_listHead;
int m_nItemHeight;
CFont font_normal_;
BASListSeqOrder order_;
bool paint_cross_bg_color_;
int nitem_hover_;
int nitem_leave_;
};
#endif
#include "stdafx.h"
#include "bas_list_view.h"
#include
#include
#include
#include
#include "utils.h"
BASListView::BASListView()
{
m_default_photo_ = NULL;
m_nItemHeight = 60;
photo_func_ = NULL;
render_func_ = NULL;
m_crEven=(RGB(255,255,255));
m_crOdd=(RGB(245,245,245));
m_checkbox_yes_ = NULL;
m_checkbox_no_ = NULL;
nitem_hover_ = -1;
nitem_leave_ = -1;
}
BASListView::~BASListView()
{
Detach();
}
void BASListView::RefreshCell(int nCol,int nRow)
{
CRect rcItem;
int column_width = GetColumnWidth(nCol);
GetSubItemRect(nRow,nCol,LVIR_SELECTBOUNDS,rcItem);
rcItem.right = rcItem.left+column_width;
InvalidateRect(rcItem);
}
void BASListView::RefreshColumn(int nCol)
{
int col_width = GetColumnWidth(nCol);
int width = col_width;
for(int i = 0; i<nCol;++i)
{
width += GetColumnWidth(i);
}
CRect rect;
GetClientRect(&rect);
rect.left = width-col_width;
rect.right = width;
InvalidateRect(rect);
}
void BASListView::SetDefaultPhoto(Gdiplus::Image* m_default_photo)
{
m_default_photo_ = m_default_photo;
}
void BASListView::DrawPhotoColumn(HDC hdcmem,Gdiplus::Graphics& graphics,
LPDRAWITEMSTRUCT lpDrawItemStruct,CRect& rctext,
int nCol)
{
int const kTextGap = 10;
CRect photo_rect = rctext;
Gdiplus::Image* photo = NULL;
if(photo_func_) photo = photo_func_(this,lpDrawItemStruct->itemID);
if(!photo) photo = m_default_photo_;
if(photo)
{
int height = photo->GetHeight();
int width = photo->GetWidth();
int maxHeight = photo_rect.Height()-4;
if(height > maxHeight)
height = maxHeight;
if(width > maxHeight)
width = maxHeight;
Gdiplus::Rect logo_rect;
logo_rect.X = photo_rect.left+2;
logo_rect.Y = photo_rect.top+(photo_rect.Height()-height)/2;
logo_rect.Width = width;
logo_rect.Height = height;
int offset = (photo_rect.Height()-height)/2;
photo_rect.top+=offset;
Gdiplus::Status gs = graphics.DrawImage(photo,logo_rect,0,0,
photo->GetWidth(),photo->GetHeight(),Gdiplus::UnitPixel);
photo_rect.left = logo_rect.X+logo_rect.Width+kTextGap;
}
CString str;
GetItemText(lpDrawItemStruct->itemID,nCol,str);
if(str.GetLength())
{
photo_rect.top = rctext.top;
UINT uFormat=DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS;
CSize lpSize;
::GetTextExtentPoint32(hdcmem, str, str.GetLength(), &lpSize);
photo_rect.top+=(photo_rect.Height()-lpSize.cy)/2;
DrawText(hdcmem,str,str.GetLength(),photo_rect,uFormat);
}
}
void BASListView::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
HDC hdc=lpDrawItemStruct->hDC;
CRect rcItem=lpDrawItemStruct->rcItem; //listview每项的rect,受滚动条位置影响
int nItem = lpDrawItemStruct->itemID;
CRect rcCient;
GetClientRect(rcCient); //固定listview的区域,宽度可小于rcitem
SCROLLINFO si;
si.cbSize=sizeof(SCROLLINFO);
si.fMask=SIF_POS|SIF_RANGE;
//偏移量很重要.
if (GetScrollInfo(SB_HORZ,&si))
{
m_h_offset=-si.nPos; //计算偏移 因为内存dc的rect和rcItem的原点不同
m_h_size=max(si.nMax+1,rcCient.Width());
}
else
{
m_h_offset=rcCient.left;
m_h_size=rcCient.Width();
}
CDC hdcmem;
hdcmem.CreateCompatibleDC(hdc);
CBitmap hbitmapmem;
hbitmapmem.CreateCompatibleBitmap(hdc,rcItem.Width(),rcItem.Height());
hdcmem.SelectBitmap(hbitmapmem);
CBrush hbr;
CPen hpen;
hpen.CreatePen(PS_SOLID,1,RGB(220,220,220));
hdcmem.SelectPen(hpen);
hdcmem.SelectFont(font_normal_);
if (lpDrawItemStruct->itemState & ODS_SELECTED ) //先画背景
{
hbr.CreateSolidBrush(RGB(161,219,238));
}
else
{
if(nItem == nitem_leave_){
hbr.CreateSolidBrush(m_crEven);
}else if(nItem == nitem_hover_){
hbr.CreateSolidBrush(RGB(205,236,245));
}else{
if(paint_cross_bg_color_){
if(lpDrawItemStruct->itemID % 2){
hbr.CreateSolidBrush(RGB(250,250,250));
}else{
hbr.CreateSolidBrush(m_crEven);
}
}else{
hbr.CreateSolidBrush(m_crEven);
}
}
}
hdcmem.FillRect(CRect(0,1,rcItem.Width(),rcItem.Height()),hbr);
//画item的左边
hdcmem.MoveTo(0,0,NULL);
hdcmem.LineTo(0,rcItem.Height());
//画item的右边
hdcmem.MoveTo(rcItem.Width()-1,0,NULL);
hdcmem.LineTo(rcItem.Width()-1,rcItem.Height()-1);
//画item的上边
hdcmem.MoveTo(0,0,NULL);
hdcmem.LineTo(rcItem.Width()-1,0);
//画item的底边
if(nItem == GetItemCount()-1){
hdcmem.MoveTo(0,rcItem.Height()-1,NULL);
hdcmem.LineTo(rcItem.Width()-1,rcItem.Height()-1);
}
hdcmem.SetBkMode(TRANSPARENT);
if(render_func_)
{
render_func_(hdcmem,this,lpDrawItemStruct->itemID);
}
Gdiplus::Graphics graphics(hdcmem);
DrawEveryColumnItem(hdcmem,graphics,lpDrawItemStruct);
BitBlt(hdc,rcItem.left,rcItem.top,rcItem.Width(),rcItem.Height(),hdcmem,0,0,SRCCOPY);
}
void BASListView::DrawEveryColumnItem(HDC hdcmem,Gdiplus::Graphics& graphics,
LPDRAWITEMSTRUCT lpDrawItemStruct)
{
LVCOLUMN lvc;
lvc.mask=LVCF_WIDTH|LVCF_FMT;
TCHAR szBuf[MAX_PATH]={0};
LVITEM lvi;
lvi.mask=LVIF_TEXT;
lvi.iItem=lpDrawItemStruct->itemID;
lvi.pszText=szBuf;
lvi.cchTextMax=MAX_PATH;
static const int kCheckBoxColumn = 0;
static const int kPhotoColumn = 1;
int const kTextGap = 10;
for (int nCol=0;GetColumn(nCol,&lvc);++nCol)
{
CRect rcSubItem;
if(!GetSubItemRect(lpDrawItemStruct->itemID,nCol,LVIR_LABEL,rcSubItem))
{
continue;
}
lvi.iSubItem=nCol;
GetItem(&lvi);
CRect rctext(rcSubItem.left-m_h_offset,0,rcSubItem.right-m_h_offset,rcSubItem.Height()); //相对于内存dc的item rect
int checkbox_width = 0;
int checkbox_height = 0;
if(m_checkbox_yes_)
{
checkbox_width = m_checkbox_yes_->GetWidth();
checkbox_height = m_checkbox_yes_->GetHeight();
}
if(nCol == kCheckBoxColumn)
{
rctext.left+=5+checkbox_width;
int nleft=5;
int ntop=(rcSubItem.Height()-checkbox_height)/2;
BOOL bChecked=ListView_GetCheckState(m_hWnd,lpDrawItemStruct->itemID );
if(m_checkbox_yes_)
{
Gdiplus::Rect dest_rect(nleft,ntop,checkbox_width,checkbox_height);
if(bChecked){
graphics.DrawImage(m_checkbox_yes_,dest_rect,0,0,checkbox_width,checkbox_height,
Gdiplus::UnitPixel);
}else{
graphics.DrawImage(m_checkbox_no_,dest_rect,0,0,checkbox_width,checkbox_height,
Gdiplus::UnitPixel);
}
}
std::wstringstream wss;
int id = (order_ == BASListSeqOrderAscend)?lpDrawItemStruct->itemID+1:
GetItemCount()-lpDrawItemStruct->itemID;
wss << id;
std::wstring str = wss.str();
if(str.size())
{
CRect photo_rect = rctext;
photo_rect.left = nleft + checkbox_width+kTextGap;
photo_rect.top = rctext.top;
UINT uFormat=DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS;
CSize lpSize;
::GetTextExtentPoint32(hdcmem, str.c_str(), str.size(), &lpSize);
photo_rect.top+=(photo_rect.Height()-lpSize.cy)/2;
DrawText(hdcmem,str.c_str(),str.size(),photo_rect,uFormat);
}
//GetItemData(lpDrawItemStruct->itemID);
}else if(nCol == kPhotoColumn)
{
DrawPhotoColumn(hdcmem,graphics,lpDrawItemStruct,rctext,nCol);
}else
{
CString str;
GetItemText(lpDrawItemStruct->itemID,nCol,str);
if(str.GetLength())
{
CSize lpSize;
::GetTextExtentPoint32(hdcmem, str, str.GetLength(), &lpSize);
CRect other_text_rect = rctext;
other_text_rect.top+=(other_text_rect.Height()-lpSize.cy)/2;
UINT uFormat=DT_LEFT|DT_VCENTER|DT_END_ELLIPSIS;
other_text_rect.left += kTextGap;
DrawText(hdcmem,str,str.GetLength(),other_text_rect,uFormat);
}
}
}
}
LRESULT BASListView::OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
if(!m_checkbox_yes_){
bHandled=FALSE;
return 1;
}
POINT pt={LOWORD(lParam),HIWORD(lParam)};
UINT uflag=0;
int nItem=HitTest(pt,&uflag);
if (nItem!=-1 && (uflag & LVHT_ONITEM ))
{
CRect rcItem;
int column_width = GetColumnWidth(0);
GetSubItemRect(nItem,0,LVIR_SELECTBOUNDS,rcItem);
rcItem.right = rcItem.left+column_width;
if (PtInRect(rcItem,pt)){
BOOL bCheckState = ListView_GetCheckState(m_hWnd, nItem) ;
ListView_SetCheckState( m_hWnd, nItem, !bCheckState );
SetItemState(nItem,(bCheckState)?0:LVNI_SELECTED,LVNI_SELECTED);
int checked_item = nItem;
if(bCheckState){
SetHeaderCheck(BST_UNCHECKED);
m_listHead.Invalidate();
// 获取首个check item.
int i=0;
for (;i<GetItemCount();++i){
BOOL bcheck_temp=ListView_GetCheckState(m_hWnd, i);
if(bcheck_temp){
checked_item = i;
break;
}
}
// 如果没有选中项, 默认第一个.
if(checked_item == nItem)
checked_item = 0;
}else{
int i=0;
for (;i<GetItemCount();++i){
BOOL bcheck_temp=ListView_GetCheckState(m_hWnd, i);
if(!bcheck_temp)
break;
}
if(i==GetItemCount()){
SetHeaderCheck(BST_CHECKED);
m_listHead.Invalidate();
}
}
::SendMessage(GetParent(),AA_LISTVIEWCHECKCHG,MAKEWPARAM(GetWindowLong(GWL_ID),0),checked_item);
}else{
bHandled=FALSE;
return 1;
}
}
else
{
bHandled=FALSE;
return 1;
}
return 0;
}
void BASListView::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
lpMeasureItemStruct->itemHeight=m_nItemHeight;
}
int BASListView::InsertItemTexts(int index,...)
{
int nItemIndex = InsertItem(index,L"");
int nColCount = GetHeader().GetItemCount();
va_list list;
va_start(list,index);
for (int i=0;i<nColCount;++i )
{
LPCTSTR pszText=va_arg(list,LPCTSTR);
SetItemText(nItemIndex,i,pszText);
}
va_end(list);
return nItemIndex;
}
int BASListView::AppendItemTexts(LPCTSTR pszText,...)
{
int nItemIndex = InsertItem(GetItemCount(),pszText);
int nColCount = GetHeader().GetItemCount();
va_list list;
va_start(list,pszText);
for (int i=1;i<nColCount;++i )
{
pszText=va_arg(list,LPCTSTR);
SetItemText(nItemIndex,i,pszText);
}
va_end(list);
return nItemIndex;
}
BOOL BASListView::OnEraseBkgnd(CDCHandle dc)
{
CBrush br;
CRect rcCli;
CRect rcItemsRect(0, 0, 0, 0);
int nHeadHeight = 0;
int nItems = GetItemCount();
GetClientRect(&rcCli);
CHeaderCtrl pHeadCtrl = GetHeader();
CRect rcHead;
pHeadCtrl.GetWindowRect(&rcHead);
nHeadHeight = rcHead.Height();
rcCli.top += nHeadHeight;
CRect rcItem;
if (nItems > 0)
{
CPoint ptItem;
GetItemRect(nItems - 1, &rcItem, LVIR_BOUNDS);
GetItemPosition(nItems - 1, &ptItem);
rcItemsRect.top = rcCli.top;
rcItemsRect.left = ptItem.x;
rcItemsRect.right = rcItem.right;
rcItemsRect.bottom = rcItem.bottom;
if (GetExStyle() & LVS_EX_CHECKBOXES)
rcItemsRect.left -= GetSystemMetrics(SM_CXEDGE) + 16;
}
br.CreateSolidBrush(GetBkColor());
if (rcItemsRect.IsRectEmpty())
dc.FillRect(rcCli, br);
else
{
if (rcItemsRect.left > rcCli.left) // fill left rectangle
dc.FillRect(
CRect(0, rcItemsRect.bottom, rcItemsRect.left, rcCli.bottom), br);
if (rcItemsRect.bottom < rcCli.bottom) // fill bottom rectangle
dc.FillRect(
CRect(0, rcItemsRect.bottom, rcCli.right, rcCli.bottom), br);
if (rcItemsRect.right < rcCli.right) // fill right rectangle
dc.FillRect(
CRect(rcItemsRect.right, rcCli.top, rcCli.right, rcCli.bottom), br);
}
return TRUE;
}
LRESULT BASListView::OnListViewHeaderCheck(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
BOOL checked = (BOOL)wParam;
if(!checked && nitem_hover_ != -1){
nitem_leave_ = nitem_hover_;
CRect rect;
GetItemRect(nitem_leave_,rect,LVIR_BOUNDS);
InvalidateRect(rect);
}
nitem_hover_ = -1;
for (int i=0;i<GetItemCount();++i){
ListView_SetCheckState( m_hWnd, i, checked);
SetItemState(i,(checked)?LVNI_SELECTED:0,LVNI_SELECTED);
}
GetParent().SendMessage(AA_LISTVIEW_HEADER_CHG,checked,0);
bHandled = TRUE;
return 0;
}
void BASListView::SetSelectedChecked()
{
int count = GetItemCount();
int checked_count = 0;
for(int i =0;i<count;++i){
BOOL selected = GetItemState(i,LVNI_SELECTED);
BOOL checked = GetCheckState(i);
if(selected){
if(!checked)
SetCheckState(i,TRUE);
++checked_count;
}else{
if(checked)
SetCheckState(i,FALSE);
}
}
bool checked = (count == checked_count);
if(GetHeaderChecked() != checked){
SetHeaderCheck(checked);
RefreshHeaderCheck();
}
}
BOOL BASListView::SelectItem(int nIndex)
{
if(nIndex > -1)
SetCheckState(nIndex,TRUE);
return BASListViewBase::SelectItem(nIndex);
}
BOOL BASListView::CreateListView(HWND hWndParent, ATL::_U_RECT rect,ATL::_U_MENUorID MenuOrID,
BASListSeqOrder order,bool paint_cross_bg_color,bool visible)
{
//LVS_EDITLABELS
auto flag = WS_CHILD | WS_CLIPCHILDREN|WS_TABSTOP |LVS_ALIGNLEFT|LVS_REPORT|LVS_OWNERDRAWFIXED;
if(visible)
flag |= WS_VISIBLE;
m_hWnd = Create(hWndParent,rect,0,flag,0,MenuOrID);
SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES);
CHeaderCtrl header = GetHeader();
m_listHead.SetCheckBoxImage(m_checkbox_yes_,m_checkbox_no_);
m_listHead.SubclassWindow(header);
order_ = order;
paint_cross_bg_color_ = paint_cross_bg_color;
return 0;
}
LRESULT BASListView::OnCreate(UINT umsg,WPARAM wparam,LPARAM lparam,BOOL& bHandled )
{
//button_check.SetBkgColor(RGB(226,244,234));
font_normal_ = Utils::GetHFONT(16);
ShowScrollBar(SB_BOTH,0);
bHandled=FALSE;
return 0;
}
void BASListView::SetCheckBoxImage(Gdiplus::Bitmap* m_checkbox_yes,
Gdiplus::Bitmap* m_checkbox_no)
{
m_checkbox_yes_ = m_checkbox_yes;
m_checkbox_no_ = m_checkbox_no;
}
int CALLBACK BASListView::CompareFunc(LPARAM lparam1,LPARAM lparam2,LPARAM lparamSort)
{
return 0;
}
void BASListView::SetItemHeight(int nh)
{
m_nItemHeight=nh;
CRect rcWin;
GetWindowRect(&rcWin);
WINDOWPOS wp;
wp.hwnd = m_hWnd;
wp.cx = rcWin.Width();
wp.cy = rcWin.Height();
wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
}
void BASListView::RefreshHeaderCheck()
{
m_listHead.RefreshCheckRect();
}
LRESULT BASListView::OnVScroll(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SCROLLINFO si;
si.cbSize=sizeof(SCROLLINFO);
si.fMask=SIF_ALL;
GetScrollInfo(SB_VERT,&si);
int bottom_pos = si.nPage+si.nPos;
if(LOWORD(wParam)!=SB_ENDSCROLL || bottom_pos < si.nMax)
{
bHandled = FALSE;
return 0;
}
bHandled = FALSE;
return 0;
}
LRESULT BASListView::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
POINT pt={LOWORD(lParam),HIWORD(lParam)};
UINT uflag=0;
int nitem =HitTest(pt,&uflag);
if(nitem == nitem_hover_)
return 0;
nitem_leave_ = nitem_hover_;
nitem_hover_ = nitem;
if (nitem!=-1 && (uflag & LVHT_ONITEM )){
BOOL selected = GetItemState(nitem,LVNI_SELECTED);
if(selected){
CRect rect;
GetItemRect(nitem_leave_,rect,LVIR_BOUNDS);
InvalidateRect(rect);
}else{
CRect rect_hover;
GetItemRect(nitem_hover_,rect_hover,LVIR_BOUNDS);
CRect rect_leave;
if(nitem_leave_ != -1){
GetItemRect(nitem_leave_,rect_leave,LVIR_BOUNDS);
}
rect_hover.UnionRect(rect_leave,rect_hover);
InvalidateRect(rect_hover);
}
}else{
CRect rect;
GetItemRect(nitem_leave_,rect,LVIR_BOUNDS);
InvalidateRect(rect);
}
return 0;
}
LRESULT BASListView::OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SCROLLINFO si;
si.cbSize=sizeof(SCROLLINFO);
si.fMask=SIF_ALL;
GetScrollInfo(SB_VERT,&si);
if((si.nPage+si.nPos) >= si.nMax)
{
//AutoLoadLeftData();
}
bHandled=FALSE;
return 0;
}
https://download.csdn.net/download/infoworld/11244213
List-View Window Styles
NM_CUSTOMDRAW notification code
Header Control
VListVW Sample
About List-View Controls