头文件:
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() ;
}