您的位置:首页 > 编程语言 > C语言/C++

C++MFC学习心得(四)——CListBox自绘控件碰到的一个小问题

2013-05-18 20:35 831 查看
老规矩,先贴代码

//.h
class CMyApp:public CWinApp
{
public:
	virtual BOOL InitInstance();
};
class CIconListBox:public CListBox
{
public:
	virtual BOOL PreCreateWindow(CREATESTRUCT &cs);
	virtual void MeasureItem(LPMEASUREITEMSTRUCT lpmis);
	virtual void DrawItem(LPDRAWITEMSTRUCT lpdis);
	int AddIcon(HICON hIcon);
	void ProjectImage(CDC* pDC,LPRECT pRect,COLORREF clrBackColor);
};
class CMainWnd:public CWnd
{
protected:
	int m_cxChar;
	int m_cyChar;

	CFont m_font;
	CRect m_rcImage;
	CButton m_wndGroupBox;
	CIconListBox m_wndIconListBox;
	CStatic m_wndLabel;
public:
	CMainWnd();
protected:
	virtual void PostNcDestroy();
	afx_msg int OnCreate(LPCREATESTRUCT lpcs);
	afx_msg void OnPaint();
	afx_msg void OnSetFocus(CWnd* pWnd);
	afx_msg void OnDropFiles(HDROP hDropInfo);
	afx_msg void OnSelChange();

	DECLARE_MESSAGE_MAP()
};
//.cpp
#include<afxwin.h>
#include"IconView.h"

#define IDC_LISTBOX 100

CMyApp myApp;

BOOL CMyApp::InitInstance()
{
	m_pMainWnd = new CMainWnd;
	m_pMainWnd->ShowWindow(m_nCmdShow);
	m_pMainWnd->UpdateWindow();

	return TRUE;
}
BEGIN_MESSAGE_MAP(CMainWnd,CWnd)
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_SETFOCUS()
	ON_WM_DROPFILES()
	ON_LBN_SELCHANGE(IDC_LISTBOX,OnSelChange)
END_MESSAGE_MAP()

CMainWnd::CMainWnd()
{
	CString strWndClass = AfxRegisterWndClass(
		0,
		myApp.LoadCursor(IDC_ARROW),
		(HBRUSH)(COLOR_3DFACE +1),
		myApp.LoadIcon(IDI_WINLOGO));
	CreateEx(0,
		strWndClass,
		_T("Icon View"),
		WS_OVERLAPPED|WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX,
		CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL);
	CRect rect(0,0,m_cxChar * 84,m_cyChar * 21);
	CalcWindowRect(&rect);
	SetWindowPos(NULL,0,0,rect.Width(),rect.Height(),SWP_NOZORDER|SWP_NOMOVE|SWP_NOREDRAW);
}
int CMainWnd::OnCreate(LPCREATESTRUCT lpcs)
{
	if(CWnd::OnCreate(lpcs) == -1)
		return -1;
	m_font.CreatePointFont(80,_T("MS Sans Serif"));

	CClientDC dc(this);
	CFont* pOldFont = dc.SelectObject(&m_font);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);
	m_cxChar = tm.tmAveCharWidth;
	m_cyChar = tm.tmHeight + tm.tmInternalLeading;

	dc.SelectObject(pOldFont);
	m_rcImage.SetRect(m_cxChar * 4,
		m_cyChar * 3,
		m_cxChar * 46,
		m_cyChar * 19);
	m_wndGroupBox.Create(_T("Detail"),
		BS_GROUPBOX|WS_VISIBLE|WS_CHILD,
		CRect(m_cxChar * 2,m_cyChar,m_cxChar* 48,m_cyChar * 20),
		this,
		UINT(-1));

	m_wndLabel.Create(_T("Icons"),
		WS_CHILD|WS_VISIBLE|SS_LEFT,
		CRect(m_cxChar * 50,m_cyChar,m_cxChar* 82,m_cyChar * 2),
		this);

	m_wndIconListBox.Create(WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_BORDER|LBS_NOTIFY|LBS_NOINTEGRALHEIGHT,
		CRect(m_cxChar* 50,m_cyChar* 2,m_cxChar*82,m_cyChar * 20),
		this,
		IDC_LISTBOX);

	m_wndGroupBox.SetFont(&m_font);
	m_wndLabel.SetFont(&m_font);
	DragAcceptFiles();
	return 0;
}

void CMainWnd::PostNcDestroy()
{
	delete this;
}

void CMainWnd::OnPaint()
{
	CPaintDC dc(this);
	m_wndIconListBox.ProjectImage(&dc,m_rcImage,::GetSysColor(COLOR_3DFACE));
}

void CMainWnd::OnSetFocus(CWnd* pWnd)
{
	m_wndIconListBox.SetFocus();
}
void CMainWnd::OnDropFiles(HDROP hDropInfo)
{
	int nCount = ::DragQueryFile(hDropInfo,(UINT)-1,NULL,0);
	if(nCount == 1)
	{
		m_wndIconListBox.ResetContent();
		char szFile[MAX_PATH];
		::DragQueryFile(hDropInfo,0,szFile,sizeof(szFile));
		int nIcons = (int)::ExtractIcon(NULL,szFile,(UINT)-1);
		if(nIcons)
		{
			HICON hIcon;
			for(int i = 0;i<nIcons;i++)
			{
				hIcon = ::ExtractIcon(AfxGetInstanceHandle(),szFile,i);
				m_wndIconListBox.AddIcon(hIcon);
			}
		}

		CString strWndTitle = szFile;
		strWndTitle += _T(" - Icon View");
		SetWindowText(strWndTitle);

		CClientDC dc(this);
		m_wndIconListBox.SetCurSel(0);
		m_wndIconListBox.ProjectImage(&dc,m_rcImage,::GetSysColor(COLOR_3DFACE));
	}
	::DragFinish(hDropInfo);
}
void CMainWnd::OnSelChange()
{
	CClientDC dc(this);
	m_wndIconListBox.ProjectImage(&dc,m_rcImage,::GetSysColor(COLOR_3DFACE));
}

BOOL CIconListBox::PreCreateWindow(CREATESTRUCT &cs)
{
	if(!CListBox::PreCreateWindow(cs))
		return FALSE;
	cs.style &=~(LBS_SORT|LBS_OWNERDRAWVARIABLE);
	cs.style |= LBS_OWNERDRAWFIXED;
	return TRUE;
}
void CIconListBox::MeasureItem(LPMEASUREITEMSTRUCT lpmis)
{
	lpmis->itemHeight = 36;
}
void CIconListBox::DrawItem(LPDRAWITEMSTRUCT lpdis)
{
	CDC dc;
	dc.Attach(lpdis->hDC);
	CRect rect = lpdis->rcItem;
	int nIndex = lpdis->itemID;

	CBrush* pBrush = new CBrush;
	pBrush->CreateSolidBrush(::GetSysColor((lpdis->itemState&ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW));
	dc.FillRect(rect,pBrush);

	delete pBrush;

	if(lpdis->itemState & ODS_FOCUS)
		dc.DrawFocusRect(rect);
	if(nIndex!=(UINT)-1)
		dc.DrawIcon(rect.left + 4,rect.top + 2,(HICON)GetItemData(nIndex));
	dc.Detach();
}

int CIconListBox::AddIcon(HICON hIcon)
{
	int nIndex = AddString(_T(""));
	if((nIndex != LB_ERR)&&(nIndex != LB_ERRSPACE))
		SetItemData(nIndex,(DWORD)hIcon);
	return nIndex;
}

void CIconListBox::ProjectImage(CDC* pDC,
								LPRECT pRect,
								COLORREF clrBackColor)
{
	CDC dcMem;
	dcMem.CreateCompatibleDC(pDC);

	CBitmap bitmap;
	bitmap.CreateCompatibleBitmap(pDC,32,32);
	CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap);

	CBrush* pBrush = new CBrush(clrBackColor);
	dcMem.FillRect(CRect(0,0,32,32),pBrush);
	delete pBrush;

	int nIndex = GetCurSel();
	if(nIndex != LB_ERR)
		dcMem.DrawIcon(0,0,(HICON)GetItemData(nIndex));

	pDC->StretchBlt(pRect->left,pRect->top,pRect->right - pRect->left,pRect->bottom - pRect->top,
		&dcMem,0,0,32,32,SRCCOPY);
	dcMem.SelectObject(pOldBitmap);
}


在这个程序里,是一个自绘CListBox的程序,但是,CListBox不响应SELCHANGE的消息,很纳闷,因为这是书上的原程序。

然后开始找吧,开始,以为消息映射没做好,改来改去,没什么结果。

下面,新建工程,CListBox,好的,有响应。

在下面,新建工程,自绘CListBox,没响应;推出,这是自绘的问题。。。然后找到前面,这里:

BOOL CIconListBox::PreCreateWindow(CREATESTRUCT &cs)
{
	if(!CListBox::PreCreateWindow(cs))
		return FALSE;
	cs.style &=~(LBS_SORT|LBS_OWNERDRAWVARIABLE);//原来这里是cs.style &=-(LBS_SORT|LBS_OWNERDRAWVARIABLE);
cs.style |= LBS_OWNERDRAWFIXED;
	return TRUE;
}

把第三行注释掉,好了。。。最后发现,原来是~和-的差别,最后得到,差别就是,结果最后一位差了1。即原来的表达式,算出来最后一位为0,。

查了一下,这一位是LBS_NOTIFY。征结找到了,为什么呢?

百科中是这样说的:

ON_LBN_SELCHANGE 列表框中的选择可能改变。如果选择被CListBox::SetCurSel成员函数改变,则通知不发送。此通知只适用于LBS_NOTIFY风格的列表框。无论何时用户按下箭头键,即使选择未改变,LBN_SELCHANGE通知消息都被发送给多选列表框。

看得我云里雾里,不知道他想说什么。没办法,我们还有一个文档叫做MSDN...

MSDN里是这么说的:

LBS_NOTIFY Parent window receives an input message whenever the user clicks or double-clicks a string.

LBS_NOTIFY 就是说,不管操作者单击或者双击某一项(不管这一项是不是之前选定的),父窗口会收到输入信息。如果没有这一位,就将SELCHANGE屏蔽掉了。这就是结果。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: