【在窗口上写字】

来源:互联网 发布:微商淘宝哪个好做 编辑:程序博客网 时间:2024/04/28 16:35

在窗口上写字

 

以前写过一个类似的:http://dev.csdn.net/develop/article/29/29193.shtm

 

不过没有处理好back space等问题。而且显示字体也收到限制。这个依然是个不成熟的,不过可以改进。

 

类代码:

==============================================================

---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 = RGB(0,0,255));

       ~CTextFun();

 

public:

       void Attach(HWND hWnd,HFONT hFont = NULL,

              COLORREF color = RGB(0,0,255));

       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键。如果换行,可以从类中得到高度,在下面创建一个新的类对象就可以了。

不支持上下左右光标,没有memdc的支持,因为是用NotXorPen和路径作出来的,所以文字会在叠加的时候产生干扰。 解决这些问题应该不是很困难。

 

使用:

1,  将窗体和CTextFun对象绑定。绑定中可以指定true-type字体和颜色。也可以使用默认的。m_fun为一个CTextFun对象,调用:

              m_fun.Attach(this->GetSafeHwnd());

2,显示文字可以调用EnterLeave来完成。Enter函数设置显示光标的位置,Leave函数清空保存的缓冲文字数据。如果在视图中,可以在OnLButtonDown中调用:

m_fun.Enter(point);

OnChar中,可以这么调用:

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) // 回车键,结束显示

       {

              m_fun.Leave();

              CWnd::OnChar(nChar,nRepCnt,nFlags);

              return;

       }

 

       m_fun.PushChar(nChar,true); // 普通键,再绑定的窗口上显示

       CWnd ::OnChar(nChar, nRepCnt, nFlags);

}

 

3,上面在OnChar中同步显示字符,如果要一次显示一个串呢,可以调用:

              m_fun.PushString("中国"); // 比如在OnLButtonDown中调用

 

效果如下:

 

 

测试代码等找到免费空间之后传上来的J

 

By enoloo,

8/10,2004

 

原创粉丝点击