VS2019, MFC 光标文字操作
程序员文章站
2022-07-14 09:29:45
...
1. 如何创建光标显示在view类中
1.1 创建OnCreate函数,在view类上右键>>属性,然后在选择WM消息中的OnCreate
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处理函数
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;
4.3 字符应该从插入符处插入的,所以需要一个鼠标左键的消息WM_LBUTTONDOWN。会自动生成OnLButtonDown函数。函数内容见代码和注释;
void CxxxxView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
SetCaretPos(point);//设置光标到左键按下的点,鼠标左键在哪里按下光标就到哪里。
m_strLine.Empty();//当鼠标按下,光标到新地方时,元字符串清空,以便新字符串的开始。
m_ptOrigin = point; //当鼠标左键按下时,保留左键按下的位置
CView::OnLButtonDown(nFlags, point);
}
4.4 定时器 用来实现KALAOK字幕 移动定时,看注释。设置了定时器,那么定时器消息就会送到windows消息队列。
4.4.1 定时器加了,当然要增加捕获此消息的函数。给view类增加WM_TIMER消息处理
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);
}