欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

VS2019, MFC 光标文字操作

程序员文章站 2022-07-14 09:29:45
...

1. 如何创建光标显示在view类中

1.1 创建OnCreate函数,在view类上右键>>属性,然后在选择WM消息中的OnCreate

VS2019, MFC 光标文字操作

VS2019, MFC 光标文字操作

1.2, 在Oncreate中添加如下代码(详细见代码及注释,取消代码中的注释以打开功能即可)

int CxxxxView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码
	/*一般字体的插入符 的创建
	CClientDC dc(this);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);//获取字信息

	CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);//创建插入符,除8是调试值,使得宽度符合视觉要求,读者可以更改看效果。
	ShowCaret();//显示插入符
	*/
	/*创建图形插入符
	CClientDC dc(this);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);

	bitmap.LoadBitmapW(IDB_BITMAP1);//位图的创建:在资源视图/Bitmap下,右键创建即可。
	CreateCaret(&bitmap);
	ShowCaret();
	*/
	return 0;
}

2. 向View窗口输出文字,当移动窗口的时候需要重新显示文字,所以要用到OnDraw消息处理函数。每次窗体的改变都会调OnDraw,添加如下代码

void CxxxxView::OnDraw(CDC* pDC)
{
	CSunXinjiaocheng05Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	//CString str("DengYou");//直接用字符串去构造也可以
	CString str;
	str = "xxxxxyyyyy";//因为其重载了=号.
	pDC->TextOutW(50,50,str);
	str.LoadStringW(IDS_DDDYYY);//使用资源视图>>String Table 里面的字符串,读者自己可以去创建
	pDC->TextOutW(200,200,str);
	
}

3.路径层和剪切区域,实现某部分文字不被其他(线条,颜色等)覆盖,让某部分文字显示不一样。查看如下代码注释。

void CxxxxView::OnDraw(CDC* pDC)
{
	CSunXinjiaocheng05Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	//CString str("DengYou");//直接用字符串去构造也可以
	CString str;
	str = "xxxxxyyyyy";//因为其重载了=号.
	pDC->TextOutW(50,50,str);
	str.LoadStringW(IDS_DDDYYY);//使用资源视图>>String Table 里面的字符串,读者自己可以去创建
	pDC->TextOutW(200,200,str);
	//路劲层 类似选定区域
	CSize cz = pDC->GetTextExtent(str);//获取字符的宽度和高度
	pDC->BeginPath();//注释掉这个对成句,则可以看到矩形框
	pDC->Rectangle(0,50,50+cz.cx,50+cz.cy);
	pDC->EndPath();
	//pDC->SelectClipPath(RGN_DIFF);//文字部分无网格线条
	pDC->SelectClipPath(RGN_AND);//只有文字上有网格线条
	for (int i = 0; i < 300; i += 10)//画网格 造中间留10个像素的网格,发现文字都在网格里
	{
		pDC->MoveTo(0,i);
		pDC->LineTo(300,i);
		pDC->MoveTo(i,0);
		pDC->LineTo(i,300);
	}
}

4.字符输入的功能,键盘输入字符显示到窗口上,删除,换行,字体,光标移动 模拟KALAOK字幕变色,创建定时器 等 。

4.1 首先要捕获键盘按下的消息WM_CHAR消息。增加一个WM_CHAR消息,选择后会自动生成OnChar处理函数

VS2019, MFC 光标文字操作

void CxxxxView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CClientDC dc(this);
	CFont font;//字体类
	font.CreatePointFont(300, L"华文行楷", NULL);//创建了字体"华文行楷"
	CFont * pOldFont =  dc.SelectObject(&font);//选择字体,并返回之前字体。
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);//获取字符高度
	if (0x0d == nChar)//判断回车键,
	{
		m_strLine.Empty();//换行了,从新开始新的字符串,清空之前的。
		m_ptOrigin.y += tm.tmHeight;//回车之后光标x轴不变,y轴增加一个字符高度

	}
	else if (0x8 == nChar)//处理退格(删除)键
	{
		COLORREF clr = dc.SetTextColor(dc.GetBkColor());//把文字变成背景色,
		dc.TextOutW(m_ptOrigin.x, m_ptOrigin.y, m_strLine);//输出与背景色一样的文字以产生删除效果
		m_strLine = m_strLine.Left(m_strLine.GetLength()-1);//留左边length-1的字符个数。
		dc.SetTextColor(clr);
		//删除后的文字放在最后输出
	}
	else
	{
		m_strLine += (char)nChar;//接收字符组成字符串。
	}
	CSize sz = dc.GetTextExtent(m_strLine);
	CPoint pt;
	pt.x = m_ptOrigin.x + sz.cx;//x轴,光标跟随文字输入而移动
	pt.y = m_ptOrigin.y; //y轴不变
	SetCaretPos(pt);//设置新光标

	dc.TextOutW(m_ptOrigin.x, m_ptOrigin.y, m_strLine);
	dc.SelectObject(pOldFont);//撤回到之前字体
	CView::OnChar(nChar, nRepCnt, nFlags);
}

4.2 为View类增加CString,CPoint和一个int类型的宽度值。成员并在View类构造函数里初始化为空和0;

VS2019, MFC 光标文字操作

VS2019, MFC 光标文字操作

 

4.3 字符应该从插入符处插入的,所以需要一个鼠标左键的消息WM_LBUTTONDOWN。会自动生成OnLButtonDown函数。函数内容见代码和注释;

VS2019, MFC 光标文字操作

 

void CxxxxView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	SetCaretPos(point);//设置光标到左键按下的点,鼠标左键在哪里按下光标就到哪里。
	m_strLine.Empty();//当鼠标按下,光标到新地方时,元字符串清空,以便新字符串的开始。
	m_ptOrigin = point; //当鼠标左键按下时,保留左键按下的位置
	CView::OnLButtonDown(nFlags, point);
}

4.4 定时器 用来实现KALAOK字幕 移动定时,看注释。设置了定时器,那么定时器消息就会送到windows消息队列。

VS2019, MFC 光标文字操作

4.4.1 定时器加了,当然要增加捕获此消息的函数。给view类增加WM_TIMER消息处理

VS2019, MFC 光标文字操作

 

void CxxxxView::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	//只设置了1个定时器100ms,即每隔100ms,此函数就会被调用
	//nIDEvent 表示来自多个定时器的消息,可以用来判断选择定时器消息。本例只有一个定时器所以不用判断。
	m_nWith += 5;//每次每5个像素的加
	CClientDC dc(this);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);
	CRect rect; //矩形框
	rect.left = 0;
	rect.top = 200;
	rect.right = m_nWith;
	rect.bottom = rect.top + tm.tmHeight;

	dc.SetTextColor(RGB(355,0,0));//红色
	CString str;//接下来输出文字
	str.LoadStringW(IDS_DDDYYY);//获取string资源字符。
	dc.DrawText(str, rect, DT_LEFT); //DT_LEFT 左对齐形式。从左边开始显示出字符
	//dc.DrawText(str,rect,DT_RIGHT);
	//dc.DrawText(str,rect,DT_CENTER);

	CSize sz = dc.GetTextExtent(str);
	if (m_nWith > sz.cx)//超过了字符串宽度
	{
		m_nWith = 0;//宽度清零
		dc.SetTextColor(RGB(0,255, 0));//设施文本颜色
		dc.TextOutW(0,200,str);//要以新的颜色输出才有效果
	}
	CView::OnTimer(nIDEvent);
}

 

 

注意:实例中用到的相关类和类成员请查看MSDN或其他地方搜索,提供MSDN如下:

 

 

 

链接:https://pan.baidu.com/s/1UPpu61qQMQGk4kLjYl5WbQ 
提取码:a620

 


// SunXin_jiaocheng05View.h: CSunXinjiaocheng05View 类的接口
//

#pragma once


class CSunXinjiaocheng05View : public CView
{
protected: // 仅从序列化创建
	CSunXinjiaocheng05View() noexcept;
	DECLARE_DYNCREATE(CSunXinjiaocheng05View)

// 特性
public:
	CSunXinjiaocheng05Doc* GetDocument() const;

// 操作
public:

// 重写
public:
	virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

// 实现
public:
	virtual ~CSunXinjiaocheng05View();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// 生成的消息映射函数
protected:
	afx_msg void OnFilePrintPreview();
	afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
	DECLARE_MESSAGE_MAP()
public:
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
private:
	CBitmap bitmap;
	CString m_strLine;//用来保存字符串
	CPoint m_ptOrigin;//用来保存鼠标点坐标
	int m_nWith;//用来保存宽度信息,KALAOK字幕功能使用。
public:
	afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnTimer(UINT_PTR nIDEvent);
};

#ifndef _DEBUG  // SunXin_jiaocheng05View.cpp 中的调试版本
inline CSunXinjiaocheng05Doc* CSunXinjiaocheng05View::GetDocument() const
   { return reinterpret_cast<CSunXinjiaocheng05Doc*>(m_pDocument); }
#endif

CPP


// SunXin_jiaocheng05View.cpp: CSunXinjiaocheng05View 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "SunXin_jiaocheng05.h"
#endif

#include "SunXin_jiaocheng05Doc.h"
#include "SunXin_jiaocheng05View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CSunXinjiaocheng05View

IMPLEMENT_DYNCREATE(CSunXinjiaocheng05View, CView)

BEGIN_MESSAGE_MAP(CSunXinjiaocheng05View, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CSunXinjiaocheng05View::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
	ON_WM_CREATE()
	ON_WM_CHAR()
	ON_WM_LBUTTONDOWN()
	ON_WM_TIMER()
END_MESSAGE_MAP()

// CSunXinjiaocheng05View 构造/析构

CSunXinjiaocheng05View::CSunXinjiaocheng05View() noexcept
{
	// TODO: 在此处添加构造代码
	m_strLine = "";
	m_ptOrigin = 0;
	m_nWith = 0;
}

CSunXinjiaocheng05View::~CSunXinjiaocheng05View()
{
}

BOOL CSunXinjiaocheng05View::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}

// CSunXinjiaocheng05View 绘图

void CSunXinjiaocheng05View::OnDraw(CDC* pDC)
{
	CSunXinjiaocheng05Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	//CString str("DengYou");//直接用字符串去构造也可以
	CString str;
	str = "xxxxxyyyyy";//因为其重载了=号.
	pDC->TextOutW(50,50,str);
	str.LoadStringW(IDS_DDDYYY);//使用资源视图>>String Table 里面的字符串,读者自己可以去创建
	pDC->TextOutW(200,200,str);
	//路劲层 类似选定区域
	CSize cz = pDC->GetTextExtent(str);//获取字符的宽度和高度
	pDC->BeginPath();//注释掉这个对成句,则可以看到矩形框
	pDC->Rectangle(0,50,50+cz.cx,50+cz.cy);
	pDC->EndPath();
	//pDC->SelectClipPath(RGN_DIFF);//文字部分无网格线条
	pDC->SelectClipPath(RGN_AND);//只有文字上有网格线条
	for (int i = 0; i < 300; i += 10)//画网格 造中间留10个像素的网格,发现文字都在网格里
	{
		pDC->MoveTo(0,i);
		pDC->LineTo(300,i);
		pDC->MoveTo(i,0);
		pDC->LineTo(i,300);
	}
}


// CSunXinjiaocheng05View 打印


void CSunXinjiaocheng05View::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CSunXinjiaocheng05View::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CSunXinjiaocheng05View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CSunXinjiaocheng05View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}

void CSunXinjiaocheng05View::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CSunXinjiaocheng05View::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CSunXinjiaocheng05View 诊断

#ifdef _DEBUG
void CSunXinjiaocheng05View::AssertValid() const
{
	CView::AssertValid();
}

void CSunXinjiaocheng05View::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CSunXinjiaocheng05Doc* CSunXinjiaocheng05View::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSunXinjiaocheng05Doc)));
	return (CSunXinjiaocheng05Doc*)m_pDocument;
}
#endif //_DEBUG


// CSunXinjiaocheng05View 消息处理程序


int CSunXinjiaocheng05View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码
	/*一般字体的插入符 的创建
	CClientDC dc(this);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);//获取字信息

	CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);//创建插入符,除8是调试值,使得宽度符合视觉要求,读者可以更改看效果。
	ShowCaret();//显示插入符
	*/
	//创建图形插入符
	CClientDC dc(this);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);

	bitmap.LoadBitmapW(IDB_BITMAP1);//位图的创建:在资源视图/Bitmap下,右键创建即可。
	CreateCaret(&bitmap);
	ShowCaret();
	SetTimer(1,100,NULL);//可以放到其他地方,但是要保证能被执行到,设置100ms,那么这样WM_TIMER 消息就会放到windows消息队列中。


	return 0;
}


void CSunXinjiaocheng05View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CClientDC dc(this);
	CFont font;//字体类
	font.CreatePointFont(300, L"华文行楷", NULL);//创建了字体"华文行楷"
	CFont * pOldFont =  dc.SelectObject(&font);//选择字体,并返回之前字体。
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);//获取字符高度
	if (0x0d == nChar)//判断回车键,
	{
		m_strLine.Empty();//换行了,从新开始新的字符串,清空之前的。
		m_ptOrigin.y += tm.tmHeight;//回车之后光标x轴不变,y轴增加一个字符高度

	}
	else if (0x8 == nChar)//处理退格(删除)键
	{
		COLORREF clr = dc.SetTextColor(dc.GetBkColor());//把文字变成背景色,
		dc.TextOutW(m_ptOrigin.x, m_ptOrigin.y, m_strLine);//输出与背景色一样的文字以产生删除效果
		m_strLine = m_strLine.Left(m_strLine.GetLength()-1);//留左边length-1的字符个数。
		dc.SetTextColor(clr);
		//删除后的文字放在最后输出
	}
	else
	{
		m_strLine += (char)nChar;//接收字符组成字符串。
	}
	CSize sz = dc.GetTextExtent(m_strLine);
	CPoint pt;
	pt.x = m_ptOrigin.x + sz.cx;//x轴,光标跟随文字输入而移动
	pt.y = m_ptOrigin.y; //y轴不变
	SetCaretPos(pt);//设置新光标

	dc.TextOutW(m_ptOrigin.x, m_ptOrigin.y, m_strLine);
	dc.SelectObject(pOldFont);//撤回到之前字体
	CView::OnChar(nChar, nRepCnt, nFlags);
}


void CSunXinjiaocheng05View::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	SetCaretPos(point);//设置光标到左键按下的点,鼠标左键在哪里按下光标就到哪里。
	m_strLine.Empty();//当鼠标按下,光标到新地方时,元字符串清空,以便新字符串的开始。
	m_ptOrigin = point; //当鼠标左键按下时,保留左键按下的位置
	CView::OnLButtonDown(nFlags, point);
}


void CSunXinjiaocheng05View::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	//只设置了1个定时器100ms,即每隔100ms,此函数就会被调用
	//nIDEvent 表示来自多个定时器的消息,可以用来判断选择定时器消息。本例只有一个定时器所以不用判断。
	m_nWith += 5;//每次每5个像素的加
	CClientDC dc(this);
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);
	CRect rect; //矩形框
	rect.left = 0;
	rect.top = 200;
	rect.right = m_nWith;
	rect.bottom = rect.top + tm.tmHeight;

	dc.SetTextColor(RGB(355,0,0));//红色
	CString str;//接下来输出文字
	str.LoadStringW(IDS_DDDYYY);//获取string资源字符。
	dc.DrawText(str, rect, DT_LEFT); //DT_LEFT 左对齐形式。从左边开始显示出字符
	//dc.DrawText(str,rect,DT_RIGHT);
	//dc.DrawText(str,rect,DT_CENTER);

	CSize sz = dc.GetTextExtent(str);
	if (m_nWith > sz.cx)//超过了字符串宽度
	{
		m_nWith = 0;//宽度清零
		dc.SetTextColor(RGB(0,255, 0));//设施文本颜色
		dc.TextOutW(0,200,str);//要以新的颜色输出才有效果
	}
	CView::OnTimer(nIDEvent);
}

 

相关标签: MFC visual studio