VS2019, MFC 光標文字操作

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);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章