MFC——自绘控件(从CWND派生的edit控件)

头文件:

typedef enum tagBKMod{COLOR_MOD, PICTURE_MOD, TRANSPARENT_MOD}BKMod;

class CTextWnd : public CWnd
{
	int m_cxChar ;		//字符的平均宽度
	int m_cyChar ;		//字符的平均高度
	int m_nTextPos ;	//字符位置的索引
	int m_nTextLimit ;	//文本框的最大宽度

	COLORREF	m_clrBK ;	//背景颜色
	COLORREF	m_clrText;	//文字颜色
	COLORREF	m_clrFram;	//边框颜色

	CPoint m_ptCaretPos ;	//当前光标位置
	CPoint m_ptTextOrigin ;	//字符输入的初始位置
	CString m_strInput ;	//输入的字符串内容

	CRect	m_rcClient ;	//客户区矩形
	CBitmap m_bmpBK ;

	BKMod m_bkmMod ;			//背景模式

	void DrawInputText(CDC *pDC) ;
	void PositionCaret(CDC *pDC = NULL) ;
	int	GetNearestPos(CPoint pt) ;

public:
	void SetClrBK(COLORREF clr) ;
	void SetClrText(COLORREF clr) ;
	void SetClrFrame(COLORREF clr) ;
	void SetBitmapBK(UINT uID) ;
	DECLARE_DYNAMIC(CTextWnd)

public:
	CTextWnd();
	virtual ~CTextWnd();

protected:
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnMButtonDown(UINT nFlags, CPoint point);
	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnSetFocus(CWnd* pOldWnd);
	afx_msg void OnKillFocus(CWnd* pNewWnd);
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
	afx_msg void OnPaint();
};


源文件

// TextWnd.cpp : 实现文件
//

#include "stdafx.h"
#include "COwnerDrawNew.h"
#include "TextWnd.h"


// CTextWnd

IMPLEMENT_DYNAMIC(CTextWnd, CWnd)

CTextWnd::CTextWnd()
{
	m_ptCaretPos.x = 0 ;
	m_ptCaretPos.y = 0 ;
	m_nTextPos = 0 ;
	m_ptTextOrigin.x =2 ;
	m_ptTextOrigin.y = 2 ;

	m_clrBK = RGB(0,200,0) ;
	m_clrFram = RGB(200,0,0) ;
	m_clrFram = RGB (0,0,200) ;

	m_bkmMod = TRANSPARENT_MOD ;
}

CTextWnd::~CTextWnd()
{
}


BEGIN_MESSAGE_MAP(CTextWnd, CWnd)
	ON_WM_MBUTTONDOWN()
	ON_WM_ERASEBKGND()
	ON_WM_SETCURSOR()
	ON_WM_CREATE()
	ON_WM_LBUTTONDOWN()
	ON_WM_SETFOCUS()
	ON_WM_KILLFOCUS()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_CHAR()
	ON_WM_PAINT()
END_MESSAGE_MAP()



// CTextWnd 消息处理程序

void CTextWnd::OnMButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CWnd::OnMButtonDown(nFlags, point);
}


BOOL CTextWnd::OnEraseBkgnd(CDC* pDC)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	if (TRANSPARENT_MOD == m_bkmMod)
	{
		pDC->SetBkMode(TRANSPARENT) ;
	}

	else if (COLOR_MOD == m_bkmMod)
	{
		CRect rc; 
		GetUpdateRect(&rc); 
		pDC->FillSolidRect(rc,m_clrBK) ;
	}

	else if (PICTURE_MOD == m_bkmMod)
	{
		CRect rect;
		GetClientRect(&rect);

		//CBitmap m_pBmp;
		BITMAP bm;
		CDC dcMem;

		//m_pBmp.LoadBitmap(IDB_BITMAP1);
		m_bmpBK.GetBitmap(&bm);//得到位图尺寸

		dcMem.CreateCompatibleDC(pDC);
		CBitmap* pOldBitmap = dcMem.SelectObject(&m_bmpBK);

		pDC->SetStretchBltMode(COLORONCOLOR);
		pDC->StretchBlt(0,0,rect.Width() ,rect.Height(),
			&dcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
		dcMem.SelectObject(pOldBitmap);
	}

	return TRUE ;
	//return CWnd::OnEraseBkgnd(pDC);
}


BOOL CTextWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{	
	if (nHitTest == HTCLIENT)
	{
		::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_IBEAM)) ;
		return TRUE ;
	}
	return CWnd::OnSetCursor(pWnd, nHitTest, message);
}


int CTextWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	TEXTMETRIC tm ;
	CClientDC dc(this) ;
	dc.GetTextMetrics(&tm) ;
	m_cxChar = tm.tmAveCharWidth ;
	m_cyChar = tm.tmHeight ;

	GetClientRect(m_rcClient) ;

	//m_bmpBK.LoadBitmap(IDB_BITMAP1) ;
	// TODO:  在此添加您专用的创建代码

	return 0;
}

void CTextWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (m_rcClient.PtInRect(point))
	{
		m_nTextPos = GetNearestPos(point) ;
		PositionCaret() ;
	}

	CWnd::OnLButtonDown(nFlags, point);
}

void CTextWnd::OnSetFocus(CWnd* pOldWnd)
{
	//CWnd::OnSetFocus(pOldWnd);
	CreateSolidCaret(2,m_cyChar) ;
	SetCaretPos(m_ptCaretPos) ;
	ShowCaret() ;
	// TODO: 在此处添加消息处理程序代码
}

void CTextWnd::OnKillFocus(CWnd* pNewWnd)
{
	//CWnd::OnKillFocus(pNewWnd);
	HideCaret() ;
	m_ptCaretPos = GetCaretPos() ;
	::DestroyCaret() ;
	// TODO: 在此处添加消息处理程序代码
}


void CTextWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch(nChar)
	{
	case  VK_LEFT:
		if (m_nTextPos != 0)
		{
			m_nTextPos -- ;
			PositionCaret() ;
		}
		break;

	case  VK_RIGHT:
		if (m_nTextPos != m_strInput.GetLength())
		{
			m_nTextPos ++ ;
			PositionCaret() ;
		}
		break ;
	}

	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}


void CTextWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}

void CTextWnd::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CClientDC dc(this) ;

	switch(nChar)
	{

	case VK_BACK:
		if (m_nTextPos != 0)
		{
			m_strInput =  m_strInput.Left(m_nTextPos - 1) +
				m_strInput.Right(m_strInput.GetLength() - m_nTextPos) ;
			m_nTextPos -- ;
		}
		break;

	default:
		if ((nChar >= 0) && (nChar <=31))
		{
			return ;
		}
		if (m_nTextPos == m_strInput.GetLength())
		{
			m_strInput += (TCHAR)nChar ;
			m_nTextPos ++ ;
		}
		else
		{
			m_strInput.Insert(m_nTextPos,nChar) ;
			m_nTextPos ++ ;
		}
		break;
	}
	HideCaret() ;
	DrawInputText(&dc) ;
	PositionCaret(&dc) ;
	ShowCaret() ;
	CWnd::OnChar(nChar, nRepCnt, nFlags);
}

void  CTextWnd::DrawInputText(CDC *pDC) 
{
	pDC->ExtTextOutW(m_ptTextOrigin.x, m_ptTextOrigin.y, ETO_OPAQUE, m_rcClient, m_strInput,NULL) ;	
	Invalidate() ;
}

//设置光标位置
void CTextWnd::PositionCaret(CDC *pDC ) 
{
	BOOL bRelease = FALSE ;

	if (pDC == NULL)
	{
		pDC = GetDC() ;
		bRelease = TRUE ;
	}

	//获取从开始到索引位置的字符串
	CPoint point = m_ptTextOrigin ;
	CString string = m_strInput.Left(m_nTextPos) ;

	//光标位置应为:起始位置 + 字符串长度(像素)
	point.x += (pDC->GetTextExtent(string, string.GetLength()).cx) ;
	SetCaretPos(point) ;

	if (pDC->GetSafeHdc())
	{
		ReleaseDC(pDC) ;
	}
}

BOOL CTextWnd::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	switch(pMsg->message)
	{
	case WM_CHAR:
		OnChar(pMsg->wParam,pMsg->lParam & 0xffff,pMsg->lParam) ;
		break;

	case WM_KEYDOWN:
		OnKeyDown(pMsg->wParam,pMsg->lParam & 0xffff,pMsg->lParam) ;
		break; 

	}
	return CWnd::PreTranslateMessage(pMsg);
}


LRESULT CTextWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	// TODO: 在此添加专用代码和/或调用基类

	return CWnd::WindowProc(message, wParam, lParam);
}


void CTextWnd::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	// TODO: 在此处添加消息处理程序代码
	// 不为绘图消息调用 CWnd::OnPaint()
	dc.SetBkMode(TRANSPARENT) ;
	dc.SetTextColor(m_clrText) ;

	if (m_bkmMod == PICTURE_MOD)
	{
		dc.TextOut(m_ptTextOrigin.x,m_ptTextOrigin.y, m_strInput) ;
	}
	else
	{
		dc.ExtTextOutW(m_ptTextOrigin.x, m_ptTextOrigin.y, ETO_OPAQUE, m_rcClient, m_strInput,NULL) ;	
	}
	
	
	
	CRect rect = m_rcClient ;
	//rect.InflateRect(-1,-1,-1,-1) ;
	dc.FrameRect(rect, &CBrush(m_clrFram)) ;
}


//此函数返回距离单击未知最近的字符的索引
int	CTextWnd::GetNearestPos(CPoint pt) 
{
	//如果单击未知小于初始位置要把光标放到第一个字符前,所以返回0
	if (pt.x <= m_ptTextOrigin.x)
	{
		return 0;
	}

	//如果鼠标单击位置大于初始位置+字符串长度(像素)那么返回最后一个字符的索引
	CClientDC dc(this) ;
	int nLen = m_strInput.GetLength() ;
	if (pt.x >=(m_ptTextOrigin.x + (dc.GetTextExtent(m_strInput,nLen).cx)))
	{
		return nLen ;
	}

	int i = 0 ;
	int nPrevChar = m_ptTextOrigin.x ;
	int nNextChar = m_ptTextOrigin.x ;

	//找出鼠标单击位置在哪两个字符之间(每次增加一个字符,计算字符串长度,当长度大于落点位置时返回)
	while(nNextChar < pt.x)
	{
		i++ ;
		nPrevChar = nNextChar ;
		nNextChar = m_ptTextOrigin.x + (dc.GetTextExtent(m_strInput.Left(i),i).cx) ;
	}

	//比较落点位置,距离前一个字符近,还是后一个字符近
	return ((pt.x - nPrevChar) < (nNextChar - pt.x)) ? i-1 : i ;
}

void CTextWnd::SetClrBK(COLORREF clr) 
{
	m_clrBK = clr ;
	m_bkmMod = COLOR_MOD ;
	Invalidate() ;
}

void CTextWnd::SetClrText(COLORREF clr)
{
	m_clrText = clr ;
	Invalidate() ;
}


void CTextWnd::SetClrFrame(COLORREF clr)
{
	m_clrFram = clr ;
	Invalidate() ;
}

void CTextWnd::SetBitmapBK(UINT uID) 
{
	m_bkmMod = PICTURE_MOD ;
	m_bmpBK.LoadBitmap(uID) ;
	Invalidate() ;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值