1. 程式人生 > >MFC 畫線,畫刷,文字

MFC 畫線,畫刷,文字

CPaintDC dc(this);//只能在OnPaint函式中使用
CClientDC dc(this);//在哪裡使用都可以

畫直線

獲得裝置描述表—>MoveTo -->LineTo

CClientDC dc(this);
	dc.MoveTo(m_myPoint);
	dc.LineTo(point);

畫連續直線

思路: 滑鼠按下時,變數flag為true,記初始點座標;在滑鼠移動訊息處理函式下,當flag為true,獲得裝置描述表 MoveTo LineTo
最重要的是: 滑鼠移動時,訊息終點為下一個的起始點
滑鼠左鍵按下:

m_myPoint = point;
m_bDrawFlag = true;

在滑鼠移動時:OnMouseMove()

if(true == m_bDrawFlag)//畫連續的線,前一段的終點是此段的起點
	{
		CClientDC dc(this);
		dc.MoveTo(m_myPoint);
		dc.LineTo(point);
		m_myPoint = point;//如果沒有這個,則畫的線起點是一個,終點不同而已,
	}

畫刷

  • 簡單畫刷 :主要做填充
    獲得裝置描述表–> 定義畫刷物件—>填充
   CBrush brush(RGB(255,0,0));
	CClientDC dc(this);
	dc.FillRect(CRect(m_myPoint,point),&brush);
  • 點陣圖畫刷
    思路:獲得裝置描述表—>定義點陣圖物件–>載入點陣圖–>定義畫刷物件–>填充
   CClientDC dc(this);
	CBitmap bitmap;
	bitmap.LoadBitmap(IDB_BITMAP1);//不想有虛線 可以新增標頭檔案 resource.h
	CBrush brush(&bitmap);
	dc.FillRect(CRect(m_myPoint,point),&brush);

字型 CFont::CreatePointFont

如果在OnDraw中就不需要獲取裝置描述表
思路: 建立物件 -> 選入裝置描述表中 -> 輸出TextOut即可 -> 恢復原來的字型

   CFont::CFont font;
	font.CreatePointFont(500,_T("楷體"));
	CFont *pOldFont = pDC->SelectObject(&font);//將新的font物件選入裝置描述表,該函式返回的 被替代的物件的指標
	pDC->TextOutW(200,50,_T("hello"));
	pDC->SelectObject(pOldFont);//恢復原來的環境

	pDC->TextOutW(200,150,_T("hello"));//為了測試,是不是恢復了預設的字型

輸出:
第一行: 一個很大字型的 hello
第二行 : 一個很小字型的 hello

任意位置的 插入符 CWnd::CreateSolidCaret

建立–》顯示–》移動–》必須要時要隱藏
函式:CWnd::CreateSolidCaret實體
函式:CreateCaret 需要CBitmap
在檢視中,OnCreate中建立,是因為: 在視窗建立之前建立插入符是沒有任何意義的,所以在視窗建立完後在建立插入符,故在OnCreate中

  1. 一般插入符:
CreateSolidCaret(100,100);//太大啦,不和諧,獲取字型資訊
ShowCaret();

發現建立的插入符太太太大了。。。怎麼辦呢?獲取環境的插入符資訊,然後給新的插入符,按照一定比例來建立。
2. 根據上下文環境設定插入符

   //建立視窗後再建立插入符,就可以,沒有視窗,建立插入符也沒啥作用
	//獲取字型資訊
	CClientDC dc(this);
    TEXTMETRIC text;//字型資訊結構體
	dc.GetTextMetrics(&text);//之前給text定義的LPTEXTMETRIC  顯示 引數不相容
	CreateSolidCaret(text.tmAveCharWidth/8,text.tmHeight);//太大啦,不和諧,獲取字型資訊
	ShowCaret();

3. 任意位置插入插入符 SetCaretPos(point);
SetCaretPos(point);//移動插入符
滑鼠左鍵:任意位置 設定游標位置

任意位置點選鍵盤輸入字元

在上面任意 位置 點選 就顯示插入符的基礎上,寫字型:

a. 定義全域性變數 CString m_strCon; CPoint m_point;//TextOut中需要
b. 滑鼠左鍵按下時,
清空m_strCon.Text("");或者 m_strCon.Empty();
m_point = point;//點選位置寫入
作用: 寫入時不會把上一次的內容也顯示上
c. 鍵盤訊息在WM_CHAR中處理:
在文件中顯示輸入字元TextOut

//鍵盤中輸入內容
	m_strCon += (TCHAR)nChar;

	//寫字型  在CDC中
	CClientDC dc(this);
	dc.TextOutW(m_myPoint.x,m_myPoint.y,m_strCon);

發現上面游標並沒有跟著走:而且原來寫的前面還有一個游標:
【解決方法】獲取字串的尺寸資訊,在起點座標的基礎上,加上這個尺寸資訊就可以啦

//鍵盤中輸入內容
	m_strCon += (TCHAR)nChar;

	//寫字型  在CDC中
	CClientDC dc(this);

	//游標隨著輸入走
	CSize size = dc.GetTextExtent(m_strCon);/獲取字串的尺寸資訊
	int x = m_myPoint.x + size.cx;//不能是 m_strCon.GetLength();
	int y = m_myPoint.y;
	SetCaretPos(CPoint(x,y));

	//輸出字型//起點座標不能改
	dc.TextOutW(m_myPoint.x,m_myPoint.y,m_strCon);//這個必須是原來的位置,就是在按下的時候的位置  

任意位置的字元的換行、退格

void CDrawLineView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此新增訊息處理程式程式碼和/或呼叫預設值

	//鍵盤中輸入內容

	//寫字型  在CDC中
	CClientDC dc(this);
	
	if(nChar == VK_RETURN)//換行
	{
		m_strCon.Empty();
		TEXTMETRIC text;//字型資訊結構體
	    dc.GetTextMetrics(&text);
		m_myPoint.y += text.tmHeight;
	}
	else if(nChar == VK_BACK)//重新寫
	{
	//先用白色背景重新寫一個全的,然後在寫一個去掉的
		COLORREF col = dc.GetBkColor();
		COLORREF Old = dc.SetTextColor(col);
		dc.TextOutW(m_myPoint.x,m_myPoint.y,m_strCon);
		m_strCon = m_strCon.Left(m_strCon.GetLength() - 1);
		dc.SetTextColor(Old);
	}
	else
	{
		m_strCon += (TCHAR)nChar;;
	}

	//游標隨著輸入走
	CSize size = dc.GetTextExtent(m_strCon);
	int x = m_myPoint.x + size.cx;
	int y = m_myPoint.y;
	SetCaretPos(CPoint(x,y));

	//輸出字型
	dc.TextOutW(m_myPoint.x,m_myPoint.y,m_strCon);

	CView::OnChar(nChar, nRepCnt, nFlags);
}

字型顏色隨時間變化,像歌詞

m_nWidth為全域性 int

if(nIDEvent == 12)
	{
		m_nWidth += 5;//+= 50時 顯示不全
		CString str = _T("hello,hello,show up if you  want to have something ,you must do your best !");
		CClientDC dc(this);
		
		CSize size = dc.GetTextExtent(str);
		if(m_nWidth > size.cx)
		{
			m_nWidth = 0;
			Invalidate(false);//介面重新整理
		}
		//先獲得原來的顏色
		dc.TextOutW(200,50,str);
		COLORREF col = dc.GetTextColor();
		dc.SetTextColor(RGB(255,0,0));//設定新的顏色
		dc.DrawText(str,CRect(200,50,200 + m_nWidth,50 + size.cy),DT_BOTTOM);
		dc.SetTextColor(col);//恢復原來顏色
	}

函式InValidate()

原型:void Invalidate( BOOL bErase = TRUE );
功能: 該函式的作用是使整個視窗客戶區無效。視窗的客戶區無效意味著需要重繪。
bErase 決定了在傳送WM_PAINT之前是否傳送WM_ERASEBKGND.

Invalidate: 函式: 是重新整理視窗,呼叫這個函式會產生訊息WM_PAINT 程式會相應ONDraw或者OnPaint函式
bErase = false 時 不擦除背景色,直接繪圖;
bErase = true 時 需要擦除背景色,會出現 刷屏的現象

InvalidateRect():

該函式的功能與Invalidate基本一樣,不同的是,它是使指定的某個區域無效,需要輸入一個區域,如果引數為NULL,則設定整個視窗為無效區。

函式UpdateWindow( )

原型:BOOL UpdateWindow(HWND hWnd );// hWnd 要更新的視窗的控制代碼
UpdateWindow函式就傳送一個WM_PAINT訊息來更新指定視窗的客戶區。

UpdateWindow( )的作用是使視窗立即重繪。呼叫Invalidate等函式後窗口不會立即重繪,這是由於WM_PAINT訊息的優先順序很低,它需要等訊息佇列中的其它訊息傳送完後才能被處理。呼叫UpdateWindow函式可使WM_PAINT被直接傳送到目標視窗,從而導致視窗立即重繪。
關於這幾個函式的具體用法,見連結
【總結】
1.新增變數方式:選中所屬類,新增變數 變數型別CPoint 可以自己輸入,這樣子的話可以,新增的變數會有初始化
2.在VS2010中資源時會有曲線,可以新增標頭檔案 resource.h 就沒有曲線啦,這個VS2010就是有點問題哦
3. 有多個LineTo時:
pDC->MoveTo(20,20);
pDC->LineTo(40,40);//
pDC->LineTo(50,87);//這個LineTo的起點 (MoveTo)就是上一個 LineTo的點,所以是一個折線:
線段一 點(20,20)到(40,40)
線段二 點(40,40)到(50,87)
4. 多個MoveTo時:
pDC->MoveTo(20,20);
pDC->MoveTo(40,40);//
pDC->LineTo(50,87);
最後只有一條線段: 點 (40,40)到點(50,87) ,第一個MoveTo的點就被忽略了。
5. SelectObject 函式
功能: 將新的font物件選入裝置描述表,
返回值:該函式返回的 被替代的物件的指標
CFont *pOldFont = pDC->SelectObject(&font);//該函式返回的 被替代的物件的指標
再次使用的時候:pDC->SelectObject(pOldFont); 恢復成原來的,如果在輸出時,字型就變成預設的字型了,而不是自己設定的字型。
所以,在使用CPen CBrush CFont BitMap 時 一定要對SelectObject成對使用
6. 函式CDC::GetTextMetrics 獲得裝置的字型資訊,使用時,必須的CClientDC dc(this); 必須獲得裝置描述表
7. CSize CDC::GetTextExtent(const CString& str) const; //獲取字串的尺寸資訊
8. CDC::GetTextMetrics()//獲取字元的資訊,高度與7中cy大小是一樣子的
9. GetTextColor
COLORREF GetTextColor() const; 獲得當前字型的顏色
virtual COLORREF SetTextColor(COLORREF crColor );設定當前字型顏色