久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

MFC繪圖總結(jié)(4):畫圖 | 求索閣

 hello663 2014-07-02
在Windows中,繪圖一般在視圖窗口的客戶區(qū)進(jìn)行,,使用的是設(shè)備上下文類CDC中各種繪圖函數(shù),。
1. 映射模式與坐標(biāo)系
1)默認(rèn)映射模式
映射模式(map mode)影響所有的圖形和文本繪制函數(shù),它定義(將邏輯單位轉(zhuǎn)換為設(shè)備單位所使用的)度量單位和坐標(biāo)方向,,Windows總是用邏輯單位來繪圖,。

缺省情況下,繪圖的默認(rèn)映射模式為MM_TEXT,,其繪圖單位為像素(只要不打印輸出,,屏幕繪圖使用該模式就夠了)。若窗口客戶區(qū)的寬和高分別為w和h像素,,則其x坐標(biāo)是從左到右,,范圍為0 ~ w-1;y坐標(biāo)是從上到下,,范圍為0 ~ h-1,。

2)設(shè)置映射模式
可以使用CDC類的成員函數(shù)GetMapMode和SetMapMode來獲得和設(shè)置當(dāng)前的映射模式:
int GetMapMode( ) const; // 返回當(dāng)前的映射模式

virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式

 
映射模式的nMapMode取值與含義
符號常量
數(shù)字常量
x方向
y方向
邏輯單位的大小
MM_TEXT
1
向右
向下
像素
MM_LOMETRIC
2
向右
向上
0.1 mm
MM_HIMETRIC
3
向右
向上
0.01 mm
MM_LOENGLISH
4
向右
向上
0.01 in
MM_HIENGLISH
5
向右
向上
0.001 in
MM_TWIPS
6
向右
向上
1/1440 in
MM_ISOTROPIC
7
自定義
自定義
自定義
MM_ANISOTROPIC
8
自定義
自定義
自定義
 
可見,除了兩種自定義映射模式外,,x方向都是向右,,y方向也只有MM_TEXT的向下,其余的都是向上,,與數(shù)學(xué)上一致,。除了MM_ANISOTROPIC外,其他所有映射模式的x與y方向的單位都是相同的,。所有映射模式的邏輯坐標(biāo)的原點(diǎn)(0, 0)最初都是在窗口的左上角,,但在CScrollView的派生類中,,MFC會隨用戶滾動文檔而自動調(diào)整邏輯原點(diǎn)的相對位置(改變視點(diǎn)的原點(diǎn)屬性)。
3)自定義映射模式
自定義映射模式MM_ISOTROPIC(各向同性,,x與y方向的單位必須相同)和MM_ANISOTROPIC(各向異性,,x與y方向的單位可以不同)的單位和方向,可以通過用CDC類的成員函數(shù)G/SetWindowExt和G/SetViewportExt來獲取/設(shè)置窗口和視口的大小來確定:
CSize GetWindowExt( ) const;

virtual CSize SetWindowExt( int cx, int cy );

virtual CSize SetWindowExt( SIZE size );
CSize GetViewportExt( ) const;

virtual CSize SetViewportExt( int cx, int cy );

virtual CSize SetViewportExt( SIZE size );
其中,,cx或size.cx和cy或size.cy分別為窗口/視口的寬度與高度(邏輯單位),。
還可以用CDC類的成員函數(shù)SetViewportOrg來設(shè)置坐標(biāo)原點(diǎn)的位置:
virtual CPoint SetViewportOrg( int x, int y );
CPoint SetViewportOrg( POINT point );
例如
void CDrawView::OnDraw(CDC* pDC) {
       CRect rect;
       GetClientRect(rect);
       pDC->SetMapMode(MM_ANISOTROPIC);
       pDC->SetWindowExt(1000,1000);

       pDC->SetViewportExt(rect.right, -rect.bottom);

       pDC->SetViewportOrg(rect.right / 2, rect.bottom /2);

       pDC->Ellipse(CRect(-500, -500, 500, 500));

}
將當(dāng)前的映射模式設(shè)置為各向異性自定義映射模式,窗口大小為1000個邏輯單位寬和1000個邏輯單位高,,視口大小同當(dāng)前客戶區(qū),,視口的坐標(biāo)原點(diǎn)設(shè)置在當(dāng)前客戶區(qū)的中央。由于使用了負(fù)數(shù)作為SetViewportExt函數(shù)的第2個參數(shù),,所以y軸方向是向上的,。
 
可見,圓被畫成了橢圓,,x與y方向上的邏輯單位不相同,。
4)單位轉(zhuǎn)換
對所有非MM_TEXT映射模式,有如下重要規(guī)則:

CDC的成員函數(shù)(如各種繪圖函數(shù))具有邏輯坐標(biāo)參數(shù)

CWnd的成員函數(shù)(如各種響應(yīng)函數(shù))具有設(shè)備坐標(biāo)參數(shù)(如鼠標(biāo)位置point)

位置的測試操作(如CRect的PtInRect函數(shù))只有使用設(shè)備坐標(biāo)時才有效

長期使用的值應(yīng)該用邏輯坐標(biāo)保存(如窗口滾動后保存的設(shè)備坐標(biāo)就無效了)

 
因此,,為了使應(yīng)用程序能夠正確工作,,除MM_TEXT映射模式外,其他映射模式都需要進(jìn)行單位轉(zhuǎn)換,。下面是邏輯單位到設(shè)備單位(如像素)的轉(zhuǎn)換公式:
x比例因子 = 視口寬度 / 窗口寬度
y比例因子 = 視口高度 / 窗口高度
設(shè)備x = 邏輯x * x比例因子 + x原點(diǎn)偏移量
設(shè)備y = 邏輯y * y比例因子 + y原點(diǎn)偏移量
Windows的GDI負(fù)責(zé)邏輯坐標(biāo)和設(shè)備坐標(biāo)之間的轉(zhuǎn)換,,這可以調(diào)用CDC類的成員函數(shù)LPtoDP和DPtoLP來進(jìn)行:

void LPtoDP( LPPOINT lpPoints, int nCount = 1 ) const;

void LPtoDP( LPRECT lpRect ) const;
void LPtoDP( LPSIZE lpSize ) const;

void DPtoLP( LPPOINT lpPoints, int nCount = 1 ) const;

void DPtoLP( LPRECT lpRect ) const;
void DPtoLP( LPSIZE lpSize ) const;
例如:

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {

              CRect rect = m_rect; // 邏輯坐標(biāo)

              CClientDC dc(this);
              dc.SetMapMode(MM_LOENGLISH);
              dc.LPtoDP(rect); // 轉(zhuǎn)化成設(shè)備坐標(biāo)

       if (rect.PtInRect(point)) // 位置的測試操作只有使用設(shè)備坐標(biāo)時才有效

       ......
}

void CDrawView:: OnMouseMove (UINT nFlags, CPoint point) {

       float t,y;

              char buf[40];

       CDC* pDC = GetDC();

pDC->SetMapMode(MM_HIMETRIC);
              pDC->DPtoLP(&point); // 轉(zhuǎn)化成邏輯坐標(biāo)

t = t1 + (point.x * dt) / w; sprintf(buf, "%.4fs", t); pSB->SetPaneText(xV, buf);

y = (y0 - point.y) / dy; sprintf(buf, "%.4f", y); pSB->SetPaneText(yV, buf);
       ......
}
2. 畫像素點(diǎn)
畫像素點(diǎn)就是設(shè)置像素點(diǎn)的顏色,從前面3)(2)已知道這可由CDC的成員函數(shù)SetPixel來做,,該函數(shù)的原型為:

COLORREF SetPixel( int x, int y, COLORREF crColor ); 

COLORREF SetPixel( POINT point, COLORREF crColor );

其中,,x與y分別為像素點(diǎn)的橫坐標(biāo)與縱坐標(biāo),crColor為像素的顏色值,。例如

pDC->SetPixel(i, j, RGB(r, g, b));

3.畫線狀圖
在Windows中,,線狀圖必須用筆來畫(筆的創(chuàng)建與使用見前面的3)(3)),下面是CDC類中可以繪制線狀圖的常用成員函數(shù):

當(dāng)前位置:設(shè)置當(dāng)前位置為(x, y)或point:(返回值為原當(dāng)前位置的坐標(biāo))

CPoint MoveTo( int x, int y ); 或 CPoint MoveTo( POINT point );

畫線:使用DC中的筆從當(dāng)前位置畫線到點(diǎn)(x, y)或point:(若成功返回非0值):

BOOL LineTo( int x, int y ); 或BOOL LineTo( POINT point );

畫折線:使用DC中的筆,,依次將點(diǎn)數(shù)組lpPoints中的nCount(≥2)個點(diǎn)連接起來,,形成一條折線:

BOOL Polyline( LPPOINT lpPoints, int nCount );

畫多邊形:似畫折線,但還會將最后的點(diǎn)與第一個點(diǎn)相連形成多邊形,,并用DC中的刷填充其內(nèi)部區(qū)域:

BOOL Polygon( LPPOINT lpPoints, int nCount );

畫矩形:使用DC中的筆畫左上角為(x1, y1),、右下角為(x2, y2)或范圍為*lpRect的矩形的邊線,并用DC中的刷填充其內(nèi)部區(qū)域:

BOOL Rectangle( int x1, int y1, int x2, int y2 ); 或
BOOL Rectangle( LPCRECT lpRect );
              有時需要根據(jù)用戶給定的兩個任意點(diǎn)來重新構(gòu)造左上角和右下角的點(diǎn),,例如:

              rect = CRect(min(p0.x, point.x), min(p0.y, point.y), max(p0.x, point.x), max(p0.y, point.y));

畫圓角矩形:使用DC中的筆畫左上角為(x1, y1),、右下角為(x2, y2)或范圍為*lpRect的矩形的邊線,并用寬x3或point.x高y3或point.y矩形的內(nèi)接橢圓倒角,,再用DC中的刷填充其內(nèi)部區(qū)域:

BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 );
BOOL RoundRect( LPCRECT lpRect, POINT point );
例如:

int d = min(rect.Width(), rect.Height()) / 4;

pDC-> RoundRect(rect, CPoint(d, d));

畫(橢)圓:使用DC中的筆在左上角為(x1, y1),、右下角為(x2, y2)或范圍為*lpRect的矩形中畫內(nèi)接(橢)圓的邊線,,并用DC中的刷填充其內(nèi)部區(qū)域:

BOOL Ellipse( int x1, int y1, int x2, int y2 );
BOOL Ellipse( LPCRECT lpRect );
注意,CDC中沒有畫圓的專用函數(shù),。在這里,,圓是作為橢圓的(寬高相等)特例來畫的。

畫?。?x1, y1)與(x2, y2)或lpRect的含義同畫(橢)圓,,(x3, y3)或ptStart為弧的起點(diǎn),(x4, y4)或ptEnd為弧的終點(diǎn):(逆時針方向旋轉(zhuǎn))

BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );

BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);

BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd);
畫圓?。海ㄆ渲?x, y)為圓心,、nRadius為半徑、fStartAngle為起始角,、fSweepAngle為弧段跨角)

BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);

畫弓弦:參數(shù)的含義同上,,只是用一根弦連接弧的起點(diǎn)和終點(diǎn),形成一個弓形,,并用DC中的刷填充其內(nèi)部區(qū)域:

BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
4.畫填充圖
在Windows中,,面狀圖必須用刷來填充(刷的創(chuàng)建與使用見前面的3)(4)),。上面(2)中的Polygon,、Rectangle、Ellipse和Chord等畫閉合線狀圖的函數(shù),,只要DC中的刷不是空刷,,都可以用來畫對應(yīng)的面狀圖(邊線用當(dāng)前筆畫,內(nèi)部用當(dāng)前刷填充),。下面介紹的是CDC類中只能繪制面狀圖的其他常用成員函數(shù):

畫填充矩形:用指定的刷pBrush畫一個以lpRect為區(qū)域的填充矩形,,無邊線,填充區(qū)域包括矩形的左邊界和上邊界,,但不包括矩形的右邊界和下邊界:

void FillRect( LPCRECT lpRect, CBrush* pBrush );

畫單色填充矩形:似FillRect,,但只能填充單色,不能填充條紋和圖案:

void FillSolidRect( LPCRECT lpRect, COLORREF clr );
void FillSolidRect( int x, int y, int cx, int cy, COLORREF clr );

畫餅圖(扇形):參數(shù)含義同Arc,,但將起點(diǎn)和終點(diǎn)都與外接矩形的中心相連接,,形成一個扇形區(qū)域,用DC中的刷填充整個扇形區(qū)域,,無另外的邊線:

BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd );

畫拖動的矩形:先擦除線寬為sizeLast,、填充刷為pBrushLast的原矩形lpRectLast,然后再以線寬為size,、填充刷為pBrush畫新矩形lpRectLast,。矩形的邊框用灰色的點(diǎn)虛線畫,缺省的填充刷為空刷:

void DrawDragRect( LPCRECT lpRect, SIZE size, LPCRECT lpRectLast,

SIZE sizeLast, CBrush* pBrush = NULL, CBrush* pBrushLast = NULL );

如:pDC->DrawDragRect(rect, size, rect0, size);

填充區(qū)域:

用當(dāng)前刷從點(diǎn)(x, y)開始向四周填充到顏色為crColor的邊界:

BOOL FloodFill(int x, int y, COLORREF crColor); // 成功返回非0

用當(dāng)前刷從點(diǎn)(x, y)開始向四周填充:

BOOL ExtFloodFill(int x, int y, COLORREF crColor,

UINT nFillType); // 成功返回非0

nFillType = FLOODFILLBORDER:填充到顏色為crColor的邊界(同F(xiàn)loodFill),;(用于填充內(nèi)部顏色不同但邊界顏色相同的區(qū)域)
nFillType = FLOODFILLSURFACE:填充所有顏色為crColor的點(diǎn),,直到碰到非crColor顏色的點(diǎn)為止,。(點(diǎn)(x, y)的顏色也必須為crColor),(用于填充內(nèi)部顏色相同但邊界顏色可以不同的區(qū)域),。例如:

pDC->ExtFloodFill(point.x, point.y, pDC->GetPixel(point), FLOODFILLSURFACE);

5.清屏
Windows沒有提供專門的清屏函數(shù),,可以調(diào)用CWnd的下面兩個函數(shù)調(diào)用來完成該功能:
void Invalidate(BOOL bErase = TRUE);
void UpdateWindow( );
或調(diào)用CWnd的函數(shù)
BOOL RedrawWindow(

   LPCRECT lpRectUpdate = NULL,

   CRgn* prgnUpdate = NULL,

   UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE

);
來完成。
例如(菜單項(xiàng)ID_CLEAR的事件處理函數(shù)):
CDrawView::OnClear() { // 調(diào)用OnDraw來清屏
       //Invalidate();
       //UpdateWindow( );
       RedrawWindow( );
}
也可以用畫填充背景色矩形的方法來清屏,,如:
       RECT rect;
       GetClientRect(&rect);

       pDC->FillSolidRect(&rect, RGB(255, 255, 255));

6.在控件上繪圖
可以在對話框資源中放置圖片控件,,并對其類型屬性選Frame??稍趯υ捒虻睦L圖消息響應(yīng)函數(shù)OnPaint或其他函數(shù)中,,用CWnd類的函數(shù)GetDlgItem:
CWnd* GetDlgItem( int nID ) const;
來獲得圖片控件的窗口對象,再用函數(shù)GetDC:

CDC* GetDC( );

由窗口對象得到DC,,然后就可以用該DC在控件中畫圖,。如(在ID為IDC_HUESAT的圖片控件上畫調(diào)色板)
void CColorDlg::OnPaint()
{
       if (IsIconic()) {
              ... ...
       }
       else {
              CDialog::OnPaint();
              int i, j;
              BYTE r, g, b;

              // get control window and DC of Hue&Saturation

              CWnd *pWin = GetDlgItem(IDC_HUESAT);

              CDC *pDC = pWin->GetDC();

              // draw hue-saturation palette

              for (i = 0; i < 360; i++)

                     for (j = 0; j <= 255; j++) {

                            HSLtoRGB(i, 255 - j, 128, r, g, b); // 自定義函數(shù),見網(wǎng)絡(luò)硬盤的

// res目錄中的ColTrans.cpp文件

                            pDC->SetPixel(i, j, RGB(r, g, b));

                     }
              ... ...
       }
}
在非Frame類靜態(tài)控件上繪圖,,必須先按順序依次調(diào)用CWnd類的Invalidate和UpdateWindow函數(shù)后,,再開始用DC畫圖。如在一個ID為IDC_COLOR的按鈕上繪圖:
void CComDlgDlg::DrawColor()
{

       CWnd* pWnd = GetDlgItem(IDC_COLOR);

       CDC* pDC = pWnd->GetDC();

       CRect rect;

       pWnd->GetClientRect(&rect);
       pWnd->Invalidate();
       pWnd->UpdateWindow();
       pDC->FillRect(&rect, new CBrush(m_crCol));
}
 
若干說明

除了基于對話框的程序外,,其他對話框類都需要自己添加(重寫型)消息響應(yīng)函數(shù)OnInitDialog,,來做一些必要的初始化對話框的工作。添加方法是:先在項(xiàng)目區(qū)選中“類視圖”頁,,再選中對應(yīng)的對話框類,,然后在屬性窗口的“重寫”頁中添加該函數(shù);

為了使在運(yùn)行時能夠不斷及時更新控件的顯示(主要是自己加的顯式代碼),,可以將自己繪制控件的所有代碼都全部加入對話框類的消息響應(yīng)函數(shù)OnPaint中,。在需要時(例如在繪圖參數(shù)修改后),自己調(diào)用CWnd的Invalidate和UpdateWindow函數(shù),,請求系統(tǒng)刷新對話框和控件的顯示,。因?yàn)榭丶彩谴翱冢丶惗际荂Wnd的派生類,。所以在對話框和控件中,,可以像在視圖類中一樣,調(diào)用各種CWnd的成員函數(shù),。

一般的對話框類,,缺省時都沒有明寫出OnPaint函數(shù)??梢宰约涸趯υ捒蝾愔刑砑覹M_PAINT消息的響應(yīng)函數(shù)OnPaint來進(jìn)行一些繪圖工作,。

為了在鼠標(biāo)指向按鈕時,讓按鈕上自己繪制的圖形不被消去,,可以設(shè)置按鈕控件的“Owner Draw”屬性為“True”,。

如果希望非按鈕控件(如圖片控件和靜態(tài)文本等),,也可以響應(yīng)鼠標(biāo)消息(如單擊、雙擊等),,需要設(shè)置控件的“Notify”屬性為“True”,。

使用OnPaint函數(shù)在對話框客戶區(qū)的空白處(無控件的地方)繪制自己的圖形,必須屏蔽掉其中缺省的對對話框基類的OnPaint函數(shù)的調(diào)用:

//CDialog::OnPaint();

對話框的背景色,,可以用CWnd類的成員函數(shù):

DWORD GetSysColor( int nIndex);
得到,,其中的nIndex取為COLOR_BTNFACE。例如:
dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
 
下面是部分例子代碼:(其中FillColor和ShowImg為自定義的成員函數(shù))
void CSetDlg::OnBnClickedPenColor()
{
       // TODO: 在此添加控件通知處理程序代碼

       CColorDialog colDlg(m_crLineColor);

       if (colDlg.DoModal() == IDOK) {

              m_crLineColor = colDlg.GetColor();

              Invalidate();
              UpdateWindow();
       }
}
// ……
void CSetDlg::OnPaint()
{

       CPaintDC dc(this); // device context for painting

       // TODO: 在此處添加消息處理程序代碼
       // 不為繪圖消息調(diào)用 CDialog::OnPaint()

       FillColor(IDC_PEN_COLOR, m_crLineColor);

       FillColor(IDC_BRUSH_COLOR, m_crBrushColor);

       if(m_pBitmap0 != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp0);

       else if(m_pBitmap != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp);

}

void CSetDlg::FillColor(UINT id, COLORREF col)

{

       CWnd* pWnd = GetDlgItem(id);

       CDC* pDC = pWnd->GetDC();

       pDC->SelectObject(new CPen(PS_SOLID, 1, RGB(0, 0, 0)));

       pDC->SelectObject(new CBrush(col));

       CRect rect;
       pWnd->GetClientRect(&rect);
       pWnd->Invalidate();
       pWnd->UpdateWindow();

       pDC->RoundRect(&rect, CPoint(8, 8));

}

void CSetDlg::ShowImg(UINT ID, HBITMAP hBmp)

{

       CWnd* pWnd = GetDlgItem(ID);

       CDC* pDC = pWnd->GetDC();

       CRect rect;
       pWnd->GetClientRect(&rect);
       pWnd->Invalidate();
       pWnd->UpdateWindow();
       BITMAP bs;

       GetObject(hBmp, sizeof(bs), &bs);

       CDC dc;

       if(dc.CreateCompatibleDC(pDC)) {

              int x0, y0, w, h;

              float rx = (float)bs.bmWidth / rect.right,

                     ry = (float)bs.bmHeight / rect.bottom;

              if (rx >= ry) {

                     x0 = 0; w = rect.right;

                     h = (int)(bs.bmHeight / rx + 0.5);

                     y0 = (rect.bottom - h) / 2;

              }
              else {

                     y0 = 0; h = rect.bottom;

                     w = (int)(bs.bmWidth / ry + 0.5);

                     x0 = (rect.right - w) / 2;

              }

              ::SelectObject(dc.GetSafeHdc(), hBmp);

              pDC->SetStretchBltMode(HALFTONE);

              pDC->StretchBlt(x0, y0, w, h, &dc, 0, 0, bs.bmWidth, bs.bmHeight, SRCCOPY);

              SetDlgItemInt(IDC_W, bs.bmWidth);

              SetDlgItemInt(IDC_H, bs.bmHeight);

       }
}
//……

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多