【在窗口上寫字】
收藏
在窗口上寫字 以前寫過一個類似的:http://dev.csdn.net/develop/article/29/29193.shtm 不過沒有處理好back space等問題。而且顯示字體也收到限制。這個依然是個不成熟的,不過可以改進(jìn)。 類代碼: ============================================================== ---TextFun.h--- /************************************************************ * Note: * A class of drawing font on any window witch was attached to * an instance of this class. * * Bugs to fit: * 1, No memory dc supported so that XORPEN maybe disturb the * existing font shape on dc. * 2, The class cannot serialize the drawing opts. * 3, On small font, the urgly face to be improved. * * By enoloo * First edition : 8/10,2004 ************************************************************/ #ifndef _TextFun_H_ #define _TextFun_H_ #include <string> #include <tchar.h> #include <windows.h> #include <assert.h> class CTextFun { public: CTextFun(){} CTextFun(HWND hWnd,HFONT hFont = NULL, COLORREF color = #0000ff); ~CTextFun(); public: void Attach(HWND hWnd,HFONT hFont = NULL, COLORREF color = #0000ff); void Enter(POINT point); void Leave(); bool IsAttached() const { return (m_hWnd != NULL && ::IsWindow(m_hWnd)); } public: bool PushChar(UINT nChar,bool bForward); void PopChar(); void PushString(LPCTSTR str2Push); std::string GetString() const { return m_strText; } long GetHeight() const { return m_nHeight; } long GetWidth() const { return (m_ptNow.x - m_ptStart.x); } POINT GetCurrentPoint() const { return m_ptNow; } protected: // create a default TRUE-TYPE font here. void CreateDefaultFont(); void _PushString(LPCTSTR str2Push,bool bForward); protected: HWND m_hWnd; HFONT m_hFont; std::string m_strText; POINT m_ptStart; POINT m_ptNow; COLORREF m_clColor; long m_nHeight; bool m_bDefaultFont; }; #endif ======================================================== ---TextFun.cpp--- #include "TextFun.h" CTextFun::CTextFun(HWND hWnd, HFONT hFont /* = NULL */, COLORREF color /* = RGB */) { Attach(hWnd,hFont,color); } CTextFun::~CTextFun() { if(m_bDefaultFont) ::DeleteObject(m_hFont); Leave(); } // NOTE: hFont must be a true type font. void CTextFun::Attach(HWND hWnd,HFONT hFont /* = NULL */, COLORREF color /* = RGB */) { assert(hWnd); assert(::IsWindow(hWnd)); m_hWnd = hWnd; HDC hdc = NULL; hdc = ::GetDC(hWnd); assert(hdc); if(hFont == NULL) { m_bDefaultFont = true; /* HFONT hft = (HFONT)::GetCurrentObject(hdc, OBJ_FONT); assert(hft); m_hFont = hft; */ CreateDefaultFont(); } else { m_bDefaultFont = false; m_hFont = hFont; } m_clColor = color; //color; HFONT oldFt = (HFONT)::SelectObject(hdc,m_hFont); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); m_nHeight = tm.tmHeight; ::SelectObject(hdc,oldFt); ::ReleaseDC(hWnd,hdc); } void CTextFun::Enter(POINT point) { m_ptStart = m_ptNow = point; ::DestroyCaret(); assert( ::CreateCaret(m_hWnd, NULL, 1, m_nHeight) ); ::ShowCaret(m_hWnd); ::SetCaretPos(point.x, point.y); } void CTextFun::Leave() { m_ptStart.x = m_ptNow.x = m_ptStart.y = m_ptNow.y = 0; m_strText.erase(); ::HideCaret(m_hWnd); ::DestroyCaret(); } // for OnChar... bool CTextFun::PushChar(UINT nChar,bool bForward) { static bool bFirstChinese = false; static char strTemp[3]; if(nChar > 127 && !bFirstChinese) // maybe a chinese char code { if(bForward) strTemp[0] = nChar; else strTemp[1] = nChar; bFirstChinese = true; return false; // wait for the second char code } else if(nChar > 127 && bFirstChinese) { if(bForward) strTemp[1] = nChar; else strTemp[0] = nChar; strTemp[2] = 0; bFirstChinese = false; } else // an ascii char code { bFirstChinese = false; // back the status here. strTemp[0] = nChar; strTemp[1] = 0; } _PushString(strTemp,bForward); return true; } void CTextFun::PopChar() { int strLength = m_strText.length(); if(m_strText.empty()) return; HDC hdc = NULL; hdc = ::GetDC(m_hWnd); assert(hdc); if(!PushChar( m_strText[strLength - 1], false )) // maybe a chinese char code { if(m_strText.empty()) { m_strText.erase(); return; } PushChar( m_strText[strLength - 2], false ); } return; } void CTextFun::_PushString(LPCTSTR str2Push,bool bForward) { // Create a caret always. int strLen = _tcsclen(str2Push); assert (strLen >= 0); assert( ::CreateCaret(m_hWnd, NULL, 1, m_nHeight) ); ::ShowCaret(m_hWnd); HDC hdc = NULL; hdc = ::GetDC(m_hWnd); assert(hdc); int preX = m_ptNow.x; // save it. LOGBRUSH logBr; logBr.lbColor = m_clColor; logBr.lbHatch = 0; logBr.lbStyle = BS_SOLID; HPEN pen,oldPen; pen = (HPEN)::ExtCreatePen( PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL, 1, &logBr, 0, NULL); // pen = (HPEN)::CreatePen(PS_SOLID,1,m_clColor); oldPen = (HPEN)::SelectObject(hdc, (HGDIOBJ)pen); HBRUSH br,oldBr; br = ::CreateSolidBrush(m_clColor); oldBr = (HBRUSH)::SelectObject(hdc, (HGDIOBJ)br); HFONT oldFt = (HFONT)::SelectObject(hdc,m_hFont); RECT rtQuery; ::DrawText(hdc, str2Push, _tcslen(str2Push), &rtQuery, DT_CALCRECT); // get the RECT for the char to draw HRGN hRgn; if(bForward) { m_ptNow.x = m_ptNow.x + (rtQuery.right - rtQuery.left); hRgn = ::CreateRectRgn(preX, m_ptNow.y, m_ptNow.x, m_ptNow.y + m_nHeight); } else { m_ptNow.x = m_ptNow.x - (rtQuery.right - rtQuery.left); hRgn = ::CreateRectRgn(m_ptNow.x, m_ptNow.y, preX, m_ptNow.y + m_nHeight); } // ::ExtSelectClipRgn(hdc,hRgn,RGN_COPY); // set the caret's pos now ::SetCaretPos(m_ptNow.x, m_ptNow.y); ::SetBkMode(hdc,TRANSPARENT); // draw the char code // ::SetPolyFillMode(hdc,ALTERNATE); int preR2 = ::SetROP2(hdc,R2_NOTXORPEN); ::BeginPath(hdc); if(bForward) ::TextOut(hdc, preX, m_ptNow.y, str2Push , _tcslen(str2Push)); else ::TextOut(hdc, m_ptNow.x, m_ptNow.y, str2Push, _tcslen(str2Push)); ::EndPath(hdc); // NOTE: DONT call a silly function StrokeAndFillPath! ::StrokeAndFillPath(hdc); // ::SelectClipPath(hdc,RGN_AND); ::SetROP2(hdc,preR2); ::SelectObject(hdc, (HGDIOBJ)oldPen); ::SelectObject(hdc, (HGDIOBJ)oldBr); ::SelectObject(hdc, (HGDIOBJ)oldFt); // save the char code if(bForward) m_strText += std::string(str2Push); else m_strText = m_strText.substr(0, m_strText.length() - _tcslen(str2Push)); return; } void CTextFun::PushString(LPCTSTR str2Push) { _PushString(str2Push,true); } void CTextFun::CreateDefaultFont() { LOGFONT lf; ::memset(&lf,0,sizeof(LOGFONT)); lf.lfHeight = 40; lf.lfWeight = /*FW_BOLD*/ FW_NORMAL; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfItalic = FALSE; lf.lfUnderline = FALSE; lf.lfStrikeOut = FALSE; lf.lfCharSet = ANSI_CHARSET; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = DRAFT_QUALITY; lf.lfPitchAndFamily = VARIABLE_PITCH | FF_MODERN; strcpy(lf.lfFaceName, "Arial"); m_hFont = ::CreateFontIndirect(&lf); } 說明: 類支持在一個和類對象綁定(Attach)的窗口上寫字,支持所有true-type字體。支持bake escape鍵。如果換行,可以從類中得到高度,在下面創(chuàng)建一個新的類對象就可以了。 不支持上下左右光標(biāo),沒有memdc的支持,因為是用NotXorPen和路徑作出來的,所以文字會在疊加的時候產(chǎn)生干擾。 解決這些問題應(yīng)該不是很困難。 使用: 1, 將窗體和CTextFun對象綁定。綁定中可以指定true-type字體和顏色。也可以使用默認(rèn)的。m_fun為一個CTextFun對象,調(diào)用: m_fun.Attach(this->GetSafeHwnd()); 2,顯示文字可以調(diào)用Enter和Leave來完成。Enter函數(shù)設(shè)置顯示光標(biāo)的位置,Leave函數(shù)清空保存的緩沖文字?jǐn)?shù)據(jù)。如果在視圖中,可以在OnLButtonDown中調(diào)用: m_fun.Enter(point); 在OnChar中,可以這么調(diào)用: void CChildView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default if(nChar == VK_BACK) // back鍵就退格,和文本框一樣 { m_fun.PopChar(); CWnd::OnChar(nChar,nRepCnt,nFlags); return; } else if(nChar == VK_RETURN) // 回車鍵,結(jié)束顯示 { m_fun.Leave(); CWnd::OnChar(nChar,nRepCnt,nFlags); return; } m_fun.PushChar(nChar,true); // 普通鍵,再綁定的窗口上顯示 CWnd ::OnChar(nChar, nRepCnt, nFlags); } 3,上面在OnChar中同步顯示字符,如果要一次顯示一個串呢,可以調(diào)用: m_fun.PushString("中國"); // 比如在OnLButtonDown中調(diào)用 效果如下: 測試代碼等找到免費空間之后傳上來的J。 By enoloo, 8/10,2004 發(fā)表于 @ 2004年08月10日 21:26:00 | 評論( 0 ) | 舉報| 收藏 舊一篇:(轉(zhuǎn)載)利用 .NET 框架簡化發(fā)布和解決 DLL Hell 問題 | 新一篇:[轉(zhuǎn)載]行進(jìn)中開火 |
|