【在窗口上写字】

原创 2004年08月10日 21:26:00

在窗口上写字<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

以前写过一个类似的: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中调用

 

效果如下:

 

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

 

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

 

By enoloo,

8/10,2004

 

VC++60 第九章 在窗体上写字

第九章 在窗体上写字 从前面的例程中我们看到,要在视窗式的应用程序中显示文字可用静态文本、编辑框和弹出消息框等方法。另外的一种方法是直接在窗口面版上写字,用这种方法还可以自由设置字体、大小和颜色...
  • GL_a_
  • GL_a_
  • 2016-10-13 17:47:32
  • 1026

VC 直接在界面上添加文字

渐变字:     // 获得窗口的客户区设备上下文句柄      CClientDC dc(this);      // 更改当前字体      LOGFONT l...
  • Leeboy_Wang
  • Leeboy_Wang
  • 2011-09-14 22:03:27
  • 1641

关于GTK怎么让一行文字在窗口上流动,求解答!

我是GTK初学者我想输入一行文字,然后让这行文字在屏幕上左右流动!
  • jikal
  • jikal
  • 2015-05-04 10:59:35
  • 268

利用标签控件显示随机验证码

 在不加背景图片的情况下,简单实现验证码生成的方法,代码如下:  protected void Page_Load(object sender, EventArgs e)    {        //...
  • taomanman
  • taomanman
  • 2009-07-27 11:35:00
  • 988

Windows程序设计-子窗口控件

按钮类别/*---------------------------------------- BTNLOOK.C -- Button Look Program (...
  • lilongsy
  • lilongsy
  • 2017-09-11 22:25:01
  • 169

窗口暴力破解软件

  • 2011年12月25日 21:44
  • 3.31MB
  • 下载

基于Qt的截图工具,实现截图后进行编辑

基于Qt的截图工具,采用了类似QQ截图的控制面板,先上效果图。 1.基本截图 2.画箭头 3.画矩形 4.画圆形 5.文字编辑 6.同时进行编辑 截图的思路主要是...
  • u012677715
  • u012677715
  • 2017-10-14 13:42:10
  • 366

判断一个view是否在主窗口

  • baohanqing
  • baohanqing
  • 2016-05-10 10:11:33
  • 257

(急求急求!!!!!!!!!!!!!!!)多线程编程:哲学家问题

设置线程,描述哲学家;   使用菜单随机启动哲学家;   在窗口上显示线程执行状态;   随着线程的执行,更新窗口的显示;   编写正确的哲学家程序,设法延迟线程的执行,使之出现死锁;   编写正确的...
  • weiyanno1
  • weiyanno1
  • 2008-06-23 22:40:00
  • 152

openCV鼠标事件学习

opencv中鼠标事件的学习
  • gu_gu_
  • gu_gu_
  • 2015-11-09 20:39:27
  • 242
收藏助手
不良信息举报
您举报文章:【在窗口上写字】
举报原因:
原因补充:

(最多只允许输入30个字)