最近因為課程需要,自己設計了一些相對簡單的繪制坐標和波形圖的函數,這些函數不夠理想,但是對於簡單要求足夠了,以后自己會逐漸的完善這些函數。這里先把他們放這里,以免找不到。
在MFC中,如果不是繪制動態波形圖,一般都要在OnPaint或者OnDraw里面進行繪制,但是大家都知道,如果把一大串的繪圖用的代碼都放到OnPaint或者OnDraw會很糾結的。如果把繪圖的代碼整理起來,放到一個或者幾個函數里面,這樣會使得代碼易懂且美觀,另外最大的優點是繪圖函數可以很好的復用,以后再用,只用改動極少的地方。這些繪圖函數就是你的經驗,就是你比別人快的地方。
我先闡述我的思路:首先,如果是繪制靜態圖,為了能夠在移動窗口時圖片依舊存在,我看到最多的方法是用雙緩存技術,這個技術我就不解釋了,百度上面多得是。繪制圖形的代碼會比較多,如果為了復用,只能把繪圖分解,這在面向對象中經常用到,我要記住,大家也要記住。因為人與人的理解會不同,所以把動作分解的方式也肯定會不一樣,我認為,只要目的達到了而且又沒有特別明顯的差距,什么樣的方法都是OK的,不能因為他是大神,他是權威,他的就是最好的,大多時候是合適的才是最好的。過多的否定自己的想法會使得自己思想僵化,總是以為自己辦不到,總以為別人的最好,我覺得這樣不利於自己成長,不利於自己原創思想的迸發。對於繪圖,首先要有筆吧,而筆呢,什么顏色?多粗?然后是你繪畫在什么地方?比如畫在紙上,你的紙張有多大?紙張的背景顏色什么?白的?黑的?。。。這些物質上的准備都是必須的吧?所以,第一個函數就是准備“筆”和“紙”的,如果有必要,自己還可以細分選擇“筆”和”紙“的動作,這里我覺得我暫時用不到,我就不再細分下去了。剩下的事情就是真正的畫圖了,畫得怎么樣就考驗個人能力了,就像畫家之間的繪畫能力一樣,畫得好,畫得差都體現在這里。當然前面選擇“筆”和選擇“紙張”也考驗人,圖形的繪制考驗人的審美能力和繪畫能力,選擇什么樣的“筆”和“紙”自己定。對於繪制波形圖,肯定先要繪制坐標框架,然后再繪制波形,因為如果先繪制波形,那么波形就會有可能被坐標框遮住一部分;同樣如果要在圖中有網格,那么肯定也是先繪制坐標框架再繪制網格最后繪制波形,這些和實際繪圖有所區別。
現在開始代碼。首先是在OnPaint里面,准備“筆”和“紙”
1 void DTTFDlg::OnPaint() 2 { 3 CPaintDC dc(this); // device context for painting 4 // TODO: 在此處添加消息處理程序代碼 5 // 不為繪圖消息調用 CDialog::OnPaint() 6 CWnd* pWnd; 7 CRect rc; 8 pWnd = GetDlgItem(IDC_STATIC_FFTPIC); 9 pWnd->GetWindowRect(rc); 10 CDC* pdc = pWnd->GetDC(); 11 StartDraw(rc,pdc,1); 12 }
准備“筆”和“紙”的函數,
1 void DTTFDlg::StartDraw(CRect rc, CDC* pdc, int flag) 2 { 3 CPen newPen; // 用於創建新畫筆 4 CPen *pOldPen; // 用於存放舊畫筆 5 CBrush newBrush; // 用於創建新畫刷 6 CBrush *pOldBrush; // 用於存放舊畫刷 7 8 int width = rc.Width(); 9 int height = rc.Height(); 10 11 //繪圖前的准備,一般不要改 12 //******************************************************************* 13 CDC MemDC; //首先定義一個顯示設備對象 14 CBitmap MemBitmap;//定義一個位圖對象 15 //隨后建立與屏幕顯示兼容的內存顯示設備 16 MemDC.CreateCompatibleDC(NULL); 17 //這時還不能繪圖,因為沒有地方畫 ^_^ 18 //下面建立一個與屏幕顯示兼容的位圖,至於位圖的大小嘛,可以用窗口的大小 19 MemBitmap.CreateCompatibleBitmap(pdc,width,height); 20 //將位圖選入到內存顯示設備中 21 //只有選入了位圖的內存顯示設備才有地方繪圖,畫到指定的位圖上 22 CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); 23 //先用背景色將位圖清除干凈,這里我用的是白色作為背景 24 //你也可以用自己應該用的顏色 25 MemDC.FillSolidRect(0,0,width,height,RGB(0,0,0)); 26 //******************************************************************* 27 28 //按照自己的情況來選擇背景顏色 29 //******************************************************************* 30 // 創建黑色新畫刷 31 newBrush.CreateSolidBrush(RGB(0,0,0)); 32 pOldBrush = MemDC.SelectObject(&newBrush); 33 // 以黑色畫刷為繪圖控件填充黑色,形成黑色背景 34 MemDC.Rectangle(rc); 35 // 恢復舊畫刷 36 MemDC.SelectObject(pOldBrush); 37 // 刪除新畫刷 38 newBrush.DeleteObject(); 39 // 創建實心畫筆,粗度為1,顏色為綠色 40 newPen.CreatePen(PS_SOLID, 1, RGB(0,255,0)); 41 // 選擇新畫筆,並將舊畫筆的指針保存到pOldPen 42 pOldPen = MemDC.SelectObject(&newPen); 43 //******************************************************************* 44 45 46 //放置要用到的繪圖函數 47 //******************************************************************* 48 //繪制網格 49 DrawPic(rc, &MemDC,1); 50 //繪制圖形 51 Plot(rc,&MemDC,1); 52 //******************************************************************* 53 54 55 //處理后事,一般不用改 56 //******************************************************************* 57 MemDC.SelectObject(pOldPen); // 恢復舊畫筆 58 newPen.DeleteObject(); // 刪除新畫筆 59 //將內存中的圖拷貝到屏幕上進行顯示 60 pdc->BitBlt(0,0,width,height,&MemDC,0,0,SRCCOPY); 61 //繪圖完成后的清理 62 MemBitmap.DeleteObject(); 63 MemDC.DeleteDC(); 64 //******************************************************************* 65 }
繪制網格,9列5行,
1 void DTTFDlg::DrawGrid(CRect rc, CDC* pdc, int flag) 2 { 3 //繪制網格的參數 4 int x = g; 5 int y = g; 6 int h = height - 2*g; 7 int w = width - 2*g; 8 int wg = (int)(w/10); 9 int hg = (int)(h/6); 10 int sg = (width - 2*g)/50; 11 12 int wi[10]; 13 int hi[5]; 14 int i; 15 //豎線 16 switch(w%10) 17 { 18 case 0: 19 for(i = 0; i < 10; i++) 20 wi[i] = wg; 21 break; 22 case 1: 23 for(i = 0; i < 10; i++) 24 { 25 if(i == 0) 26 wi[i] = wg+1; 27 else 28 wi[i] = wg; 29 } 30 break; 31 case 2: 32 for(i = 0; i < 10; i++) 33 { 34 if(i <= 1) 35 wi[i] = wg+1; 36 else 37 wi[i] = wg; 38 } 39 break; 40 case 3: 41 for(i = 0; i < 10; i++) 42 { 43 if(i <= 2) 44 wi[i] = wg+1; 45 else 46 wi[i] = wg; 47 } 48 break; 49 case 4: 50 for(i = 0; i < 10; i++) 51 { 52 if(i <= 3) 53 wi[i] = wg+1; 54 else 55 wi[i] = wg; 56 } 57 break; 58 case 5: 59 for(i = 0; i < 10; i++) 60 { 61 if(i <= 4) 62 wi[i] = wg+1; 63 else 64 wi[i] = wg; 65 } 66 break; 67 case 6: 68 for(i = 0; i < 10; i++) 69 { 70 if(i <= 5) 71 wi[i] = wg+1; 72 else 73 wi[i] = wg; 74 } 75 break; 76 case 7: 77 for(i = 0; i < 10; i++) 78 { 79 if(i <= 6) 80 wi[i] = wg+1; 81 else 82 wi[i] = wg; 83 } 84 break; 85 case 8: 86 for(i = 0; i < 10; i++) 87 { 88 if(i <= 7) 89 wi[i] = wg+1; 90 else 91 wi[i] = wg; 92 } 93 break; 94 case 9: 95 for(i = 0; i < 10; i++) 96 { 97 if(i <= 8) 98 wi[i] = wg+1; 99 else 100 wi[i] = wg; 101 } 102 break; 103 } 104 //橫線 105 switch(h%6) 106 { 107 case 0: 108 for(i = 0; i < 5; i++) 109 hi[i] = hg; 110 break; 111 case 1: 112 for(i = 0; i < 5; i++) 113 { 114 if(i == 0) 115 hi[i] = hg+1; 116 else 117 hi[i] = hg; 118 } 119 break; 120 case 2: 121 for(i = 0; i < 5; i++) 122 { 123 if(i <= 1) 124 hi[i] = hg+1; 125 else 126 hi[i] = hg; 127 } 128 break; 129 case 3: 130 for(i = 0; i < 5; i++) 131 { 132 if(i <= 2) 133 hi[i] = hg+1; 134 else 135 hi[i] = hg; 136 } 137 break; 138 case 4: 139 for(i = 0; i < 5; i++) 140 { 141 if(i <= 3) 142 hi[i] = hg+1; 143 else 144 hi[i] = hg; 145 } 146 break; 147 case 5: 148 for(i = 0; i < 5; i++) 149 { 150 if(i <= 4) 151 hi[i] = hg+1; 152 else 153 hi[i] = hg; 154 } 155 break; 156 157 } 158 159 //刻度 160 int temp1; 161 int temp2; 162 int j = 0; 163 int gi[50]; 164 for(i = 0; i < 10; i++) 165 { 166 temp1 = wi[i]/5; 167 temp2 = wi[i]%5; 168 switch(temp2) 169 { 170 case 0: 171 for(j = 0; j < 5; j++) 172 gi[5*i+j] = temp1; 173 break; 174 case 1: 175 for(j = 0; j < 5; j++) 176 { 177 if(j == 0) 178 gi[5*i+j] = temp1 + 1; 179 else 180 gi[5*i+j] = temp1; 181 } 182 break; 183 case 2: 184 for(j = 0; j < 5; j++) 185 { 186 if(j <= 1) 187 gi[5*i+j] = temp1 + 1; 188 else 189 gi[5*i+j] = temp1; 190 } 191 break; 192 case 3: 193 for(j = 0; j < 5; j++) 194 { 195 if(j <= 2) 196 gi[5*i+j] = temp1 + 1; 197 else 198 gi[5*i+j] = temp1; 199 } 200 break; 201 case 4: 202 for(j = 0; j < 5; j++) 203 { 204 if(j <= 3) 205 gi[5*i+j] = temp1 + 1; 206 else 207 gi[5*i+j] = temp1; 208 } 209 break; 210 } 211 } 212 213 214 CPen newPen; 215 CPen* pOldPen; 216 217 if(flag == 0) 218 newPen.CreatePen(PS_DOT,1,RGB(128,128,128)); //網格的顏色為灰色 219 else 220 newPen.CreatePen(PS_DOT,1,RGB(169,169,169)); //網格的顏色為深灰色 221 pOldPen = pdc->SelectObject(&newPen); //選擇畫筆 222 223 //繪制豎線 224 for(int i = 0; i < 9 ; i++) 225 { 226 x = x + wi[i]; 227 y = y + hi[i]; 228 //繪制豎虛線 229 pdc->MoveTo(x,g); 230 pdc->LineTo(x,height-g); 231 //繪制橫虛線 232 if(i < 5 && i != 2) 233 { 234 pdc->MoveTo(g,y); 235 pdc->LineTo(width-g,y); 236 } 237 } 238 239 //銷毀畫筆 240 newPen.DeleteObject(); 241 242 if(flag == 0) 243 newPen.CreatePen(PS_SOLID,1,RGB(255,255,255)); //定義畫筆,顏色為白色 244 else 245 newPen.CreatePen(PS_SOLID,1,RGB(0,0,0)); //定義畫筆,顏色為黑色 246 pdc->SelectObject(newPen); //選擇新畫筆 247 248 //繪制坐標軸的邊框 249 x = g; 250 y = g; 251 pdc->MoveTo(g,g); 252 pdc->LineTo(width-g,g); 253 pdc->MoveTo(width-g,g); 254 pdc->LineTo(width-g,height-g); 255 pdc->MoveTo(width-g,height-g); 256 pdc->LineTo(g,height-g); 257 pdc->MoveTo(g,height-g); 258 pdc->LineTo(g,g); 259 //繪制x軸軸線 260 pdc->MoveTo(x,y+3*hg); 261 pdc->LineTo(width-g,y+3*hg); 262 263 //繪制刻度 264 int x1 = g; 265 int yv = y+3*hg; 266 for(int i = 0; i < 50; i++) 267 { 268 x1 = x1 + gi[i]; 269 pdc->MoveTo(x1,yv+3); 270 pdc->LineTo(x1,yv-2); 271 } 272 273 pdc->SelectObject(pOldPen); 274 newPen.DeleteObject(); 275 }
繪制波形圖
1 CPen newPen; 2 CPen* pOldPen; 3 newPen.CreatePen(PS_SOLID,1,RGB(178,34,34)); //繪制曲線的顏色,火磚色 4 pOldPen = pdc->SelectObject(&newPen); 5 6 int height = rc.Height(); 7 int width = rc.Width(); 8 int w = width - 2*g; 9 int h = height - 2*g; 10 11 int x = g; 12 int y = g; 13 int i; 14 15 double W = double(w*100)/100.0; 16 double H = double(h*100)/100.0; 17 18 pdc->MoveTo(g,(int)(height/2)); 19 20 for(i = 0; i < m_PointNum;i++) 21 { 22 x = g + int(W*xdata.retrieveAt(i)/xdata.maxValue()); //xdata要繪圖的數據 23 y = (int)(height/2)-int(H/2*ydata.retrieveAt(i)/ydata.maxValue());//ydata要繪圖的數據 24 pdc->LineTo(x,y); 25 } 26 pdc->SelectObject(pOldPen); 27 newPen.DeleteObject();
上面出現的變量,
1 //邊框到窗口的距離 2 int g; 3 //用於存儲數據,arrayListType我自己寫的 4 arrayListType<double> xdata; 5 arrayListType<double> ydata; 6 // 用於記錄坐標點個數,在視圖類構造函數中初始化為0。 7 int m_PointNum;
