1. 程式人生 > >MFC雙快取繪圖——動態繪製模擬示波器的訊號和座標軸(附原始碼)

MFC雙快取繪圖——動態繪製模擬示波器的訊號和座標軸(附原始碼)

本文基於Visual Studio 2013的MFC函式庫和c++語言實現了軟體中類似示波器的訊號和座標軸的繪製和動態更新功能。以下為實現過程的思路介紹和雙快取繪圖和圖形塊複製等技術的介紹、實現。

1 雙快取繪圖技術

1.1 原理

雙緩衝繪圖,它是一種基本的圖形影象繪圖技術。首先,它在記憶體中建立一個與螢幕繪圖區域一致的物件,然後將圖形繪製到記憶體中的這個物件上,最後把這個物件上的圖形資料一次性地拷貝並顯示到螢幕上。這種技術能夠大大地提高繪圖的速度,減少卡頓和閃屏的問題。
卡頓問題
在應用程式開發中,當影象資訊資料量很大時,繪圖可能需要幾秒鐘甚至更長的時間,這時,應用程式可能會出現卡頓的現象。另外,如果窗體在響應WM_PAINT訊息的同時也要進行復雜的圖形處理,那麼窗體在重繪時就會由於頻繁的重新整理而引起閃爍現象,而使用雙緩衝技術就能有效地解決以上問題。
閃爍問題


窗體在重新整理時,總要有一個擦除原來圖象的過程OnEraseBkgnd,它利用背景色填充窗體繪圖區,然後再呼叫新的繪圖程式碼進行重繪,這樣一擦一寫造成了圖象顏色的反差。當WM_PAINT的響應很頻繁的時候,這種反差也就越發明顯。於是我們就看到了閃爍現象。
如果只是僅僅去掉背景色的填充,的確無論怎樣重繪圖形都不會閃了。但是那樣的話,窗體畫面往往會變的亂七八糟。因為每次繪製圖象的時候都沒有將原來的圖象清除,造成了圖象的殘留,疊加了新圖形。所以單純的禁止背景重繪是不夠的,我們還要進行重新繪圖。重新繪圖可使用 BitBlt函式,它支援圖形塊的複製,速度很快。

1.2 實現

上述原理介紹部分已經提到,在記憶體中建立一個虛擬畫板繪圖比在螢幕裝置中直接繪圖要迅速很多,可以有效解決卡頓的現象。幸運的是,Bitblt、TransparentBlt和StretchBlt函式可以將記憶體中繪製的影象快速地複製在螢幕裝置中。但只是複製就會出現之前螢幕存在的影象一直存在不被擦除的問題,所以每次要重繪時都要呼叫自定義視窗的Invalidate和UpdateWindow。Invalidate函式會將自定義視窗的所有區域設為無效,然後觸發WM_PAINT訊息導致重繪自定義視窗。此時,自定義視窗會自動呼叫OnEraseBkgnd,該函式的作用是用螢幕裝置的背景顏色填充視窗。當背景顏色與繪製的影象有顏色差異時,就會出現閃爍。為避免閃爍,需要修改自定義視窗的OnEraseBkgnd。所以,要實現雙快取繪圖功能,需要實現以下兩點:

1.在虛擬畫板中繪圖,然後複製圖形塊到螢幕裝置中。

/*1.在虛擬記憶體中建立畫板,繪製完成後複製到螢幕裝置上下文中*/
void CMyWnd::OnPaint()	//自定義視窗的WM_PAINT訊息的響應函式
{
CClient dc(this);	//螢幕裝置DC(DC,裝置上下文或稱裝置描述表)
CDC myDc;
myDc.CreateCompatible(&dc);	//建立與顯示器相容的dc
CBitmap myBmp;
myBmp.CreateCompatibleBitmap(&dc,width,height);	//建立與顯示器相容的點陣圖
myDc.SelectObject
(&myBitmap); //將點陣圖資源選入自定義的裝置描述表 ... /*myDc的繪圖實現*/ ... dc.Bitblt(x,y,w,h,&myDc,_x,_y,SRCCOPY); //將myDc的影象複製到dc中 myDc.ReleaseDC(); //釋放裝置描述表 Device Context myBmp.DeleteObject(); //釋放點陣圖資源 }

2.修改自定義視窗的OnEraseBkgnd函式,使之無效。

/* 2.修改自定義視窗的OnEraseBkgnd*/
BOOL CMyWnd::OnEraseBkgnd(CDC* pDC)
{
	// TODO:  在此新增訊息處理程式程式碼和/或呼叫預設值
	return TRUE;	//直接返回TRUE
}

2 動態繪製模擬示波器的訊號和座標軸

2.1 需求分析

訊號顯示功能的工作狀態描述如下,採集卡按照固定的取樣頻率取樣得到原始資料,然後通過USB介面源源不斷地將原始資料上傳至筆記本。軟體需要將上傳的資料實時地在顯示介面的資料通道中從左到右動態繪製訊號圖線,訊號圖線繪製到最右端時訊號清空,座標軸的橫軸刻度值更新,資料通道開始從最左端重新繪製,如此迴圈。

2.2 方案設計

本文基於Visual Studio 2013的單文件程式設計實現軟體的繪圖功能,單文件框架簡潔明瞭,且具有視覺化的選單欄、工具欄和客戶區分別滿足人機互動和繪圖的需求。本文通過在客戶區建立自定義視窗以實現資料通道的繪製功能,以下繪圖方案設計及實現均在自定義視窗的成員函式中完成。如下圖1所示,自定義視窗填滿客戶區,繪圖區域位於自定義視窗中。

圖1 繪圖區域位於客戶區的自定義視窗中

資料通道的繪製包括繪製座標軸和訊號線。座標軸在翻頁或者視窗大小改變時重繪,而訊號線要實現快速地連續繪製,訊號線重新整理快,而座標軸重新整理慢,二者的重新整理頻率相差很多。將座標軸和訊號線分別繪製在兩個點陣圖中,兩個點陣圖分別按照自己的頻率重繪以實現視窗重新整理,這樣可大大減少繪圖的工作量,在保證軟體正常執行的情況下降低對計算機執行速度的依賴。兩個點陣圖可通過圖形塊複製技術實現合併,合併之後再次複製到自定義視窗的繪圖區域。座標軸包含外面的方框、中心線、門限線以及時間橫座標,門限線用於標識訊號的幅值,超出門限線的訊號用特殊顏色繪製。
資料通道的橫座標為時間,縱座標為採集卡連線的感測器的訊號幅值。要實現訊號線的橫座標繪製準確,每個資料通道的資料量要滿足與取樣頻率成正比。打個比方,每個通道的取樣頻率為128個數據/秒,設計的每頁顯示時間為20秒,則每一頁的通道資料數量為128/20/=2560/128資料/秒*20秒/頁=2560資料/頁即資料通道從零開始寫入2560個數據之後翻頁。由於採集過程是一個取樣時間不確定的連續過程,所以訊號繪製也是一個連續的繪圖過程。訊號的連續實時繪製並不是說資料通道每上傳一個點之後都要立刻繪圖,而是採用“分段”繪製的實現方式。採集卡上傳的每個完整的資料包包含512個16位的取樣資料,而這些資料按照通道一、通道二、…通道八的順序迴圈排列,也就是說每個資料包包含64個同一通道的資料。明確了這一點,可以在每個通道錄入64個數據後觸發一次繪製訊號線,所以訊號線的重新整理頻率就是(2560/64)/20=2Hz(2560/64)/20=2Hz也就是一秒內重新整理兩次,在眼睛看起來是“連續”繪製的,但實際上還是“分段”繪製的。設計的資料通道的顯示效果如圖2所示,其中有訊號線、方框、中心線和門限線等。

圖2 單個數據通道的顯示效果 下面將詳細介紹方案的設計細節。
2.2.1 資料寫入通道快取

按照上面的設計可知,對於連續的採集過程,上傳的資料總量是不可預知的,所以提前開闢一段大小固定的記憶體空間用於儲存上傳的資料這種方案不可行。根據通道顯示時可以翻頁的特點,當前螢幕繪製滿之後自動翻頁,重繪下一螢幕。所以只要儲存當前頁面內的資料,翻頁後刪除上一頁的資料,重新儲存當前頁面內資料即可用有限的記憶體空間顯示無限的訊號資料。
設定每一頁每一通道顯示的資料量為一定值,如2560,每個資料是16位,則用一個大小為sizeof(2560USHORT)sizeof(2560*USHORT)的記憶體空間即可滿足顯示介面儲存的需求。繪圖類的實現為CDrawArea,也是自定義視窗的類實現。通道資料類CChannelData用於儲存每個通道的資料,並對其資料進行新增和刪除等操作。顯然,每個CChannelData類中都有sizeof(2560USHORT)sizeof(2560*USHORT)大小的記憶體。在CDrawArea中包含有CChannelData的八個物件分別對應八個通道。
採集卡在採集過程中會不斷髮送資料到上位機軟體,由於USB傳輸協議的要求,每次上傳原始資料的大小必須是512位元組。這些資料中並不只有繪圖所需的漏磁資料,還有標誌位和序號位,標誌位和序號位用於隔斷相鄰的資料包。原始資料的格式如圖所示。由於每個完整的資料包所佔記憶體大小大於512位元組且不是512位元組的整數倍,所以一個數據包需要分為多次傳輸。為了實現原始資料的儲存、解析,最終得到各個通道的資料,軟體開闢了子執行緒用於連續地接受採集卡上傳的資料並根據相鄰的兩個標誌位獲得其間的漏磁資料。其工作原理如下:每一次獲得512位元組的原始資料,將其新增進一個大小足夠大的陣列的尾部,並判斷當前陣列是否含有兩個標誌位,若是,則去除兩個標誌位之間的漏磁資料,並刪除第二個標誌位之前的所有資料;若否,則繼續下一次512位元組的新增,直到含有兩個標誌位。子執行緒如此迴圈即可不停地接受原始資料,並將得到的儲存漏磁資料的陣列地址作為自定義訊息的一個指標引數傳送給繪圖類CDrawArea。由於繪圖類是個視窗類CWnd的派生類,所以可以新增這個自定義訊息的響應函式來對這個訊息進行響應。訊息響應函式實際上用於傳遞漏磁資料的陣列地址,並將資料分別壓入(CChannelData::push())對應的通道,壓入完成後進行訊號點陣圖的更新,即一段訊號線的繪製。

圖3 資料包的資料結構 因此上位機軟體在獲得上傳的原始資料後,需要首先根據標誌位取出每個完整的資料包中的漏磁檢測資料,再根據每個資料包的資料結構將512個數據依次推送到8個通道,然後觸發一次訊號線繪製。流程圖如下圖所示。 圖4 資料獲取以及影象繪製的流程圖
2.2.2 繪製座標軸

座標軸在翻頁和視窗大小改變時繪製。座標軸的繪製內容包括8個並行通道的邊框、門限和橫座標,並在橫座標的刻度線位置處標明橫座標的刻度值。繪製每個通道只需要知道通道的左上頂點的座標位置和長度、寬度。八個資料通道的長度、寬度一致,區別在於左上頂點的座標位置。在軟體的介面大小更改時需要重繪座標軸。重繪時首先要根據客戶區的大小及位置得到自定義視窗的大小及位置,然後重繪座標軸及訊號線。座標軸的設計效果如下圖,外邊框與自定義視窗的邊界重合,即與視窗客戶區重合。

圖5 8個通道的座標軸繪製
2.2.3 繪製訊號線

儲存八個通道漏磁資料的動態陣列的地址由子執行緒的自定義訊息的指標引數傳入,每次共傳入512個漏磁資料,每個通道傳入64個數據,對應於訊號線的64個數據點。由於每次資料包傳入時都觸發繪圖,所以每次繪圖每個通道繪製64個數據點。訊號線的重新整理頻率為2Hz2Hz。繪製訊號時的函式呼叫情況如下圖6所示。

圖6 訊號繪製時的函式呼叫情況

2.3 軟體實現(附關鍵函式的原始碼)

2.3.1 繪製座標軸

繪製座標軸的函式為DrawAxis(),引數為選擇是否重繪座標軸的bool型別變數,引數為true時重繪。實現程式碼如下:

void CDataArea::DrawAxis(bool _reDrawFlag)
{
	CClientDC dc(this);	//得到當前螢幕的裝置上下文
	if (axisBitmap.m_hObject == NULL){	//axisBitmap為CBitmap物件,用於承載繪製的座標軸
		axisBitmap.CreateCompatibleBitmap(&dc, wndWidth, wndHeight);
	}
	else{
		if (_reDrawFlag){
			axisBitmap.DeleteObject();
			axisBitmap.CreateCompatibleBitmap(&dc, wndWidth, wndHeight);
		}
	}
	CDC axisDc;
	axisDc.CreateCompatibleDC(&dc);//建立與螢幕裝置相容的 裝置上下文/裝置描述表/dc
	axisDc.SelectObject(&axisBitmap);//將點陣圖資源選入dc
	//建立畫筆
	CPen solidPen(PS_SOLID, 1, RGB(0, 0, 0));  //邊線
	CPen dotPen(PS_DOT, 1, RGB(0, 0, 0));      //中心線
	CPen axisPen(PS_SOLID, 2, RGB(0, 0, 0));   //座標軸刻度線
	CFont axisFont;
	axisFont.CreatePointFont(40, L"Times New Roman");//建立字型
	CRect rect(0, 0, wndWidth, wndHeight);
	axisDc.FillSolidRect(rect,RGB(255, 255, 255));  //背景顏色設為白色
	axisDc.SetBkMode(TRANSPARENT);        //設定字型背景為透明
	axisDc.SetTextColor(RGB(0, 0, 0));  //設定字型顏色
	//繪製通道
	for (int i = 0; i < channelNumber; i++){
		//繪製邊線
		axisDc.SelectObject(&solidPen);
		axisDc.MoveTo(ChLeftTop_X[i], ChLeftTop_Y[i]);//ChLeftTop_X[]和ChLeftTop_Y[]分別儲存了8個通道的位置資訊
		axisDc.LineTo(ChLeftTop_X[i] + width, ChLeftTop_Y[i]);//width 和 height儲存了8個通道的大小資訊
		axisDc.LineTo(ChLeftTop_X[i] + width, ChLeftTop_Y[i] + height);
		axisDc.LineTo(ChLeftTop_X[i], ChLeftTop_Y[i] + height);
		axisDc.LineTo(ChLeftTop_X[i], ChLeftTop_Y[i]);
		//繪製座標軸刻度線
		int _w = width / 10;
		axisDc.SelectObject(&axisPen);
		for (int j = 1; j < 10; j++){
			axisDc.MoveTo(ChLeftTop_X[i] + _w*j, ChLeftTop_Y[i] + height);
			axisDc.LineTo(ChLeftTop_X[i] + _w*j, ChLeftTop_Y[i] + height - SCALE_LINE_HEIGHT);
		}
		//繪製中心線
		axisDc.SelectObject(&dotPen);
		axisDc.MoveTo(ChLeftTop_X[i], ChLeftTop_Y[i] + height / 2);
		axisDc.LineTo(ChLeftTop_X[i] + width, ChLeftTop_Y[i] + height / 2);
		//繪製門限線
		for (int j = 0; j < THRESHOLD_NUMBER; j++){
			CPen thresholdPen(PS_DOT, 1, thresholdColor[j]);
			axisDc.SelectObject(&thresholdPen);
			axisDc.MoveTo(ChLeftTop_X[i], ChLeftTop_Y[i] + thresholdOrdinate[j]);
			axisDc.LineTo(ChLeftTop_X[i] + width, ChLeftTop_Y[i] + thresholdOrdinate[j]);
		}
		//繪製座標軸刻度值
		dataBegin = (pageNumber - 1)*DATANUMBERPERPAGE;
		dataStop = dataBegin + DATANUMBERPERPAGE;
		CString coordinateValue;
		for (int j = 0; j < 10; j++){
			coordinateValue.Format(_T("%d"), dataBegin + DATANUMBERPERPAGE / 10 * j);
			axisDc.TextOutW(ChLeftTop_X[i] + _w*j, ChLeftTop_Y[i] + height + 6, coordinateValue);
		}
	}
	dc.BitBlt(0, 0, wndWidth, wndHeight, &axisDc, 0, 0, SRCCOPY);//圖形塊的複製
	//清除繪圖物件
	solidPen.DeleteObject();
	dotPen.DeleteObject();
	axisPen.DeleteObject();
	axisFont.DeleteObject();
	axisDc.DeleteDC();
}
2.3.2 繪製訊號線

繪製訊號線的函式為DrawData(),其bool型別的引數決定是否重繪訊號線,int型別的引數是資料包的序號,表徵了分段繪製時的每段資料的橫座標起點。實現程式碼如下:

void CDataArea::DrawData(bool _reDrawFlag,int serialNumber)
{
	CClientDC dc(this);
	if (dataBitmap.m_hObject == NULL){
		dataBitmap.CreateCompatibleBitmap(&dc, wnd_width, wnd_height);
	}
	else{
		if (_reDrawFlag){
			dataBitmap.DeleteObject();
			dataBitmap.CreateCompatibleBitmap(&dc, wnd_width, wnd_height);
		}
	}
	CDC dataDc;
	dataDc.CreateCompatibleDC(&dc);
	dataDc.SelectObject(&dataBitmap);
	//訊號線
	CDC lineDc;
	lineDc.CreateCompatibleDC(&dc);
	CBitmap lineBmp;
	lineBmp.CreateCompatibleBitmap(&dc, wnd_width, wnd_height);
	lineDc.SelectObject(&lineBmp);
	CPen signalPen(PS_SOLID, 2, RGB(255, 255, 255));		//建立畫筆
	lineDc.SelectObject(&signalPen);
	CRgn rgn;
	for (int i = 0; i < channelNumber; i++){		//繪製訊號線
		rgn.CreateRectRgn(ChLeftTop_X[i], ChLeftTop_Y[i], ChLeftTop_X[i] + width, ChLeftTop_Y[i] + height);
		lineDc.SelectClipRgn(&rgn);
		for (int j = 0; j < DATA_NUM_PER_PACKET; j++){
			int serial = j + serialNumber*DATA_NUM_PER_PACKET;
			chData[i].pXOrdinate[serial] = chData[i].pPacketXData[j] = width*serial / DATANUMBERPERPAGE;
			chData[i].pYOrdinate[serial] = chData[i].pPacketYData[j] = height / 2 - height*(chData[i].pPacketOriginalData[j] - dataAvg)*SENSITIVITY;
			if (j == 0){
				lineDc.MoveTo(ChLeftTop_X[i] + chData[i].pXOrdinate[serial - 1], ChLeftTop_Y[i] + chData[i].pYOrdinate[serial - 1]);
			}
			lineDc.LineTo(ChLeftTop_X[i] + chData[i].pXOrdinate[serial], ChLeftTop_Y[i] + chData[i].pYOrdinate[serial]);
		}
		rgn.DeleteObject();
	}
	//區域顏色
	CDC bkDc;
	bkDc.CreateCompatibleDC(&dc);
	CBitmap bkBmp;
	bkBmp.CreateCompatibleBitmap(&dc, wnd_width, wnd_height);
	bkDc.SelectObject(&bkBmp);
	int y0 = thresholdOrdinate[0] = height *threshold[0] / 100;
	int y1 = thresholdOrdinate[1] = height *threshold[1] / 100;
	for (int i = 0; i < channelNumber; i++){
	    CRect rect(ChLeftTop_X[i], ChLeftTop_Y[i], ChLeftTop_X[i] + width, ChLeftTop_Y[i] + y0);
		bkDc.FillSolidRect(&rect, thresholdColor[1]);
	}
	for (int i = 0; i < channelNumber; i++){	
		CRect rect(ChLeftTop_X[i], ChLeftTop_Y[i] + y0, ChLeftTop_X[i] + width, ChLeftTop_Y[i] + y1);
		bkDc.FillSolidRect(&rect, thresholdColor[0]);
	}
	for (int i = 0; i < channelNumber; i++){
		CRect rect(ChLeftTop_X[i], ChLeftTop_Y[i] + y0, ChLeftTop_X[i] + width, ChLeftTop_Y[i] + y1);
		bkDc.FillSolidRect(&rect, thresholdColor[1]);
	}
	bkDc.BitBlt(0, 0, width, height, &lineDc, 0, 0, SRCAND);
	dc.TransparentBlt(0, 0, wnd_width, wnd_height, &bkDc, 0, 0, wnd_width, wnd_height, RGB(0, 0, 0));
	//釋放物件
	bkDc.DeleteDC();
	lineDc.DeleteDC();
	dataDc.DeleteDC();
	lineBmp.DeleteObject();
	bkBmp.DeleteObject()
            
           

相關推薦

MFC快取繪圖——動態繪製模擬示波器訊號座標軸原始碼

本文基於Visual Studio 2013的MFC函式庫和c++語言實現了軟體中類似示波器的訊號和座標軸的繪製和動態更新功能。以下為實現過程的思路介紹和雙快取繪圖和圖形塊複製等技術的介紹、實現。 1 雙快取繪圖技術 1.1 原理 雙緩衝繪圖,它是一種基本的

Android後臺模擬點選探索原始碼

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出 工作中我們需要自制一套工具,其中遇到需要模擬點選事件的需求,類似按鍵精靈的功能,支援後臺持續執行,滿足觸發條件時完成點選。 經過一番探索,一共整理出兩種不同的方案:Accessibility

MFC緩衝繪圖解決介面閃爍問題

一:為什麼會產生介面閃爍? 解釋這個之前,我們需要明白的是在MFC裡面繪圖的訊息響應機制,大概的就是如果我們要在某一個 東西上面繪圖,比如對話方塊,單文件等等,就必須先得到圖形DC的控制代碼(handle),然後在指定控制代碼的基礎上進行圖形操作,也就是MFC常用的CDC *DC = this-

MFC緩衝繪圖例項

本人之前一直了解雙緩衝繪圖的基本原理,但是在研究很久之後才大概知道具體的使用過程,本文將詳細介紹本人在實際專案中使用雙緩衝繪圖的案例。 實現功能:主介面顯示某張包含人臉的圖片,通過dlib detector獲取到人臉上的68個關鍵點,繪製在圖片上顯示,然後通過滑鼠拖動圖片上的關鍵點,調整位置,之後儲存。雙緩衝

MFC緩衝繪圖

    在VC/MFC用CDC繪圖時,頻繁的重新整理,螢幕會出現閃爍的現象,CPU時間佔用率相當高,繪圖效率極低,很容易出現程式崩潰。         所謂雙緩衝技術,百度百科的解釋:雙緩衝即在記憶體中建立一個與螢幕繪圖區域一致的物

VC GDI+快取繪圖

//雙緩衝顯示影象 CRect rect; GetClientRect(&rect); CDC memDC; CBitmap MemBitmap; // 裝置描述表初始化 memD

HTML5 Canvas動態繪製心型線玫瑰線

1HTML5的Canvas元素提供了豐富的繪圖功能,能夠使我們製作出許多精美的動畫。本次將運用canvas繪製心型線和玫瑰線。 1.心型線和玫瑰線 繪製這兩種曲線,首先我們分別選用兩個引數方程(心型線和玫瑰線的引數方程不同,其形態特徵也不一樣,你可以根據你的

用Fiddler模擬低速網絡環境弱網

鏈接 一位 enter 所有 通過 repl rscript uic 限制 原文鏈接:http://caibaojian.com/fiddler.html 有時候寬頻網路用習慣了… 在開發的過程就比較少去考慮最佳化的問題… 但當有人反應說「你的網頁好慢」 甚至當網路速度慢,

Windows靜態庫動態庫的創建使用VS2005

spec 占用內存 庫文件 工程 存在 中間 開發程序 文件的 系統 偶們在實際的編程開發中,經常會遇到運行時無法找到某個DLL文件或者鏈接時無法找到某個LIB文件。然後,我們就開始亂GOOGLE一下,然後將VS2005的設置改變一下,或許就Ok了,我們將別人開發的DLL或

動態規劃:任務調度問題雙塔問題

mat 任務調度 lse system www. 地方 ava can sca 題目鏈接 兩個CPU,處理N個任務,每個任務有一個處理時長(0~4096),要把這些任務全部處理完,如何調度才能最高效? N個圓柱,要搭建兩個塔,要使這兩個塔高度之差盡量小,問較高的那座塔多高?

『8.25 模擬賽』外賣 atcoder 100e

spa lin 外賣 tco 答案 iostream 數值 ios gis 題目鏈接 題目描述 眾所周知,\(cky\)喜歡點外賣。 已知可選的商品有\(n\)種,\(cky\)由於胃容量問題只能點兩份(不能一種點兩份)。\(cky\)要在防止營養過剩的情況下選擇美味度最高

jzoj5922. 【NOIP2018模擬10.23】sequence組合數

5922. 【NOIP2018模擬10.23】sequence Description 小 F 是一位 Hack 國的居民,他生活在一條長度為 n 的街道上,這個街道上總共有 n 個商店。每個商店裡售賣著不同的 Hack 技能包,每個商店本身也會有個便利值。初始時,每個商店的便利值均

使用R語言ggplot2包繪製pathway富集分析氣泡圖Bubble圖:資料結構及程式碼

氣泡圖是在笛卡爾座標系同加入大小的引數所形成的可以表示三個變數關係的圖例。在對基因完成GO/KEGG分析後,使用氣泡圖可以直觀的展示pathway、pvalue、count之間的關係。下面為使用R語言ggplot2包繪製氣泡圖所需的資料結構及程式碼: 由於筆者常使用read.csv讀取

模擬實現strcpy函式功能優化改進

strcpy函式,字串拷貝函式,傳入兩個引數,將第二個引數的值拷貝到第一個中去。 首先,給出一個普通的程式碼: #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> void

UVA-12657 Boxes in a Line (模擬,雙向連結串列陣列實現)

第一次對陣列實現雙向連結串列的練習,理解了發現數組實現真方便… 題目:UVA-12657 題目描述: 你有n個盒子在桌子上的一條線上從左到右編號為1……n。你的任務是模擬四種操作 1 X Y 移動盒子編號X到盒子編號Y的左邊(如果X已經在Y的左邊了就忽略) 2 X Y 移

VC++6.0下基於MFC框架利用CInternetSessionCHttpFile獲取網頁資料程式碼

例:從網站http://qq.ip138.com/weather/guangdong/GuangZhou.htm獲取近三天的日期、天氣、溫度、風向,程式碼如下: //新增標頭檔案 #include <afxinet.h> //獲取網路資料 void CSensorSysDlg:

模擬_1012 The Best Rank 25 分

1012 The Best Rank (25 分) To evaluate the performance of our first year CS majored students, we consider their grades of three courses onl

spring cloud 資料來源配置,兩種方式jdbcmybatisjdbcTemplate sqlsessionTemplate及需要注意的問題

一、jdbcTemplate:jdbc application.yml檔案:     spring:       application:       

Android 動態獲取儲存、位置、電話的許可權程式碼

       今天客戶提出上傳資訊時需攜帶經緯度,且需要兩種獲取位置的方式;故經思考使用了GPS和網路獲取位置,但在經過實地測試的時候才發現沒寫獲取許可權。       便在登入介面加上獲取許可權程式碼,此次獲取的是儲存、位置

Linux程序之如何管理程序?如何動態地檢視程序的狀態?top命令

文章目錄 1. top命令的主要作用 2. top命令引數解讀 2.1 第一行 2.2 第二行 2.3 第三行 2.4 第四行 2.5 第五行 2.6 第六行為空,下面是第七行