【在窗口上写字】

原创 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
  • 903

windows窗口绘制总结

windows窗口绘制
  • ldpxxx
  • ldpxxx
  • 2015年09月15日 12:00
  • 1121

没事儿找事儿————gtk学习(给窗体添加按钮)

上一篇完善了一下窗体,但是仅仅一个窗体没有什么用,我们需要大量的其他控件。那么我们慢慢来。先从最基本的按钮开始!在上篇的基础上稍微修改代码。 #include void on_button_cli...
  • liu1164316159
  • liu1164316159
  • 2013年12月21日 15:37
  • 2066

102.使用WindowManager在窗口上显示view

WindowManager是Android中一个重要的服务(Service )。WindowManager Service 是全局的,是唯一的。它将用户的操作,翻译成为指令,发送给呈现在界面上的各个W...
  • augfun
  • augfun
  • 2017年04月06日 00:08
  • 256

lesson 2 在窗口上显示图像

//本教程的地一个垫脚石:一个弹出窗口 //现在SDL已经设置好了, 是时候做一个梗概使SDL图形程序在屏幕上渲染显示 //使用 SDL 和标准 IO #include #include //屏幕尺寸...
  • Ant_look
  • Ant_look
  • 2016年03月13日 17:33
  • 319

如何用dx画一个界面

昨天开始在我的dx小demo里边加ui,其实十分顺利的加上了……然而出了点小问题,ui无法显示在窗口的正中间……只好发到了微信群里边问了下。同事说了四个字,“正交投影”……当时我的表情是这样的:( ⊙...
  • YgritteSnow
  • YgritteSnow
  • 2016年05月18日 20:31
  • 449

使用Windows API进行GDI窗口绘图

http://blog.csdn.net/celte/article/details/10243309   使用Windows API进行GDI窗口绘图 标签: GD...
  • kakaxi2222
  • kakaxi2222
  • 2016年08月01日 20:12
  • 2468

opencv学习日记之创建滑动条和显示混合图片效果

第一个参数,const string&类型的trackbarname,表示轨迹条的名字,用来代表我们创建的轨迹条。第二个参数,const string&类型的winname,填窗口的名字,表示这个轨迹...
  • OliverkingLi
  • OliverkingLi
  • 2016年04月04日 14:48
  • 1336

利用OpenGL在窗口上绘制出三维坐标

/*今天刚开通CSDN博客,以此记录我的编程学习之旅*/ 按时间顺序来讲,这是计算机图形学课程的第一个编程实践,大概是在一年前吧。这个程序是在nehe OpenGL框架下完成的,现在回头来看,这是一...
  • Carnnation
  • Carnnation
  • 2015年03月11日 13:43
  • 5130

103.使用WindowManager在窗口上显示view的优化界面

原始的界面使用TextView看起来不是很好,现在加入自定义的样式,让效果更好 界面如下 布局文件如下toast_address.xml ...
  • augfun
  • augfun
  • 2017年04月06日 00:29
  • 294
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【在窗口上写字】
举报原因:
原因补充:

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