グラフ内のサンプル ポイントの y 軸をマウス クリックで変更できる、MFC を使用して対話型グラフを作成しようとしています。このチュートリアルを使用してダブルバッファリングを実装し
ました ここにリンクの説明を入力してください. また、プログラムのビューポートの原点を時々変更する必要があることも指摘しておく必要があります。ただし、更新するサンプル ポイントのグラフをクリックすると、まだちらつきます。不便ではありませんが、このグラフを拡張して、多くのサンプル ポイントや、グリッド線、軸、ラベル、境界領域などの他の機能を含める必要があり、ちらつきが将来的に問題になるのではないかと心配しています。このプロジェクトのサイズが大きくなります。ダブルバッファリングを実装しても、出力に変更はないようです。さらに、ダブル バッファリングを実装したので、プログラムは実行の途中で停止したように見えます (Visual Studio でデバッグ モードで実行している場合)。次のエラーが表示されます。
Unhandled exception at 0xffffff3a in graph_on_dlgbox.exe: 0xC0000005: Access violation reading location 0xffffff3a.
何が原因で表示されるのかはまだわかりませんが、グラフ領域をランダムにすばやくクリックし始めると発生するようです。ダブル バッファリングを使用しないコードでこのエラーを (まだ) 見たことがないので、ダブル バッファリング コードと関係があると思いますが、よくわかりません。
とにかく、この問題を 1 つずつ解決していきたいのですが、最初の問題はちらつきです。ダブルバッファリングのない私のコードは次のとおりです。
void Cgraph_on_dlgboxDlg::OnPaint()
{
CPaintDC dc(this);
if (IsIconic())
{
// CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
CPen pen;
COLORREF pencolour = RGB(0, 0, 0);
COLORREF brushcolour = RGB(0, 0, 255);
COLORREF graphColour = RGB(0, 0, 150);
// Draw boarder
pen.CreatePen(PS_SOLID, 3, pencolour);
// CBrush brush(HS_CROSS, brushcolour);
dc.SetBkMode(TRANSPARENT);
dc.SetMapMode(MM_TEXT);
dc.SetViewportOrg(theGraph.x1, theGraph.y1);
// Dc.SetViewportExt(theGraph.width, theGraph.height);
dc.SelectObject(&pen);
// dc.SelectObject(&brush);
// Draw graph boundary
CPoint point1(0,0);
point1.x = 0;
point1.y = 0;
CPoint point2(0,0);
point2.x = point1.x + theGraph.width;
point2.y = point1.y + theGraph.height;
dc.Rectangle(CRect(point1, point2));
pen.DeleteObject();
// Draw Horizontal at 0
pen.CreatePen(PS_SOLID, 1, pencolour);
dc.SelectObject(&pen);
dc.MoveTo(0, theGraph.height - ORG_DIST_FROM_BOTTOM);
dc.LineTo(theGraph.width, theGraph.height - ORG_DIST_FROM_BOTTOM);
pen.DeleteObject();
// Shift overall graph origin from top left corner to beginning of this horizontal line
dc.SetViewportOrg(theGraph.x1, theGraph.y1 + theGraph.height - ORG_DIST_FROM_BOTTOM); // dc.SetViewportOrg() always works relative to the clinet origin
// Draw graph line
pen.CreatePen(PS_SOLID, 2, graphColour);
dc.SelectObject(&pen);
for(int i = 0; i<NUM_OF_SECTIONS_IN_GRAPH; i++){
dc.MoveTo(graphSamplePoints[i].x, graphSamplePoints[i].y);
dc.LineTo(graphSamplePoints[i+1].x, graphSamplePoints[i+1].y);
}
// draw circles at graph sample points
for(int i = 0; i<NUM_OF_POINTS_IN_GRAPH; i++){
CIRCLE(dc, graphSamplePoints[i].x, graphSamplePoints[i].y, GRP_SMP_RAD);
}
}
ダブルバッファリングを使用した修正版は次のとおりです。
void Cgraph_on_dlgboxDlg::OnPaint()
{
// /*****
CPaintDC dc_blt(this);
CDC dc;
CBitmap bmpDC;
// CRect rcClient;
// GetClientRect(rcClient);
if (IsIconic())
{
// CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
dc.CreateCompatibleDC(&dc_blt);
// bmpDC.CreateCompatibleBitmap(&dc_blt, rcClient.Width(),rcClient.Height());
bmpDC.CreateCompatibleBitmap(&dc_blt, theGraph.width,theGraph.height );
dc.SelectObject(&bmpDC);
// ----------- After this point, do all operations considering (0,0) to be the origin of the bitmap
// consider bitmap coordinates a device coordinates for Viewport operations
CPen pen;
COLORREF pencolour = RGB(0, 0, 0);
COLORREF brushcolour = RGB(0, 0, 255);
COLORREF graphColour = RGB(0, 0, 150);
// Draw boarder
pen.CreatePen(PS_SOLID, 3, pencolour);
// CBrush brush(HS_CROSS, brushcolour);
dc.SetBkMode(TRANSPARENT);
dc.SetMapMode(MM_TEXT);
// dc.SetViewportOrg(theGraph.x1, theGraph.y1);
// dc.SetViewportExt(theGraph.width, theGraph.height);
dc.SelectObject(&pen);
// dc.SelectObject(&brush);
// Draw graph boundary
CPoint point1(0,0);
point1.x = 0;
point1.y = 0;
CPoint point2(0,0);
point2.x = point1.x + theGraph.width;
point2.y = point1.y + theGraph.height;
dc.Rectangle(CRect(point1, point2));
pen.DeleteObject();
// Draw Horizontal at 0
pen.CreatePen(PS_SOLID, 1, pencolour);
dc.SelectObject(&pen);
dc.MoveTo(0, theGraph.height - ORG_DIST_FROM_BOTTOM);
dc.LineTo(theGraph.width, theGraph.height - ORG_DIST_FROM_BOTTOM);
pen.DeleteObject();
// Shift overall graph origin from top left corner to beginning of this horizontal line
// dc.SetViewportOrg(theGraph.x1, theGraph.y1 + theGraph.height - ORG_DIST_FROM_BOTTOM); // dc.SetViewportOrg() always works relative to the client area origin
// New origin defined in terms of the Bitmap's origin
dc.SetViewportOrg(0, theGraph.height - ORG_DIST_FROM_BOTTOM);
// Draw graph line
pen.CreatePen(PS_SOLID, 2, graphColour);
dc.SelectObject(&pen);
for(int i = 0; i<NUM_OF_SECTIONS_IN_GRAPH; i++){
dc.MoveTo(graphSamplePoints[i].x, graphSamplePoints[i].y);
dc.LineTo(graphSamplePoints[i+1].x, graphSamplePoints[i+1].y);
}
// draw circles at graph sample points
for(int i = 0; i<NUM_OF_POINTS_IN_GRAPH; i++){
CIRCLE(dc, graphSamplePoints[i].x, graphSamplePoints[i].y, GRP_SMP_RAD);
}
dc.SetViewportOrg(0, 0);
// dc_blt.BitBlt(rcClient.left+100,rcClient.top+50,rcClient.Width(), rcClient.Height(), &dc, 0, 0, SRCCOPY);
// dc_blt.BitBlt(0,0,rcClient.Width(), rcClient.Height(), &dc, theGraph.x1, theGraph.y1, SRCCOPY);
dc_blt.BitBlt(theGraph.x1,theGraph.y1, theGraph.width, theGraph.height, &dc, 0, 0, SRCCOPY);
// --- Bring the bitmap to this particular location on screen specified by (theGraph.x1,theGraph.y1, theGraph.width, theGraph.height)
// dc_blt.BitBlt(0,0,theGraph.width, theGraph.height, &dc, 0, 0, SRCCOPY);
// dc_blt.BitBlt(theGraph.x1,theGraph.y1,theGraph.width, theGraph.height, &dc, 0, 0, SRCCOPY);
// *****/
m_bMyDraw = FALSE;
}
出力のサンプル スクリーンショットを次に示します。
グラフ上のサンプル ポイントの y 軸の値は、クリックすることで変更できます。プログラムは、クリックするたびInvalidateRect()
に、グラフの領域を再描画する四角形として呼び出すことにより、グラフを再描画します。
サンプル ポイントの座標は CPoint オブジェクトの配列に格納され、グラフの適切な領域がクリックされるたびにそのメンバーが更新されます。への呼び出しにより、グラフは再描画され
InvalidateRect()
ますが、ちらつきがあります。もちろん、プログラムが次のエラーでデバッグ モードでクラッシュしない限り:
ちらつきを取り除くにはどうすればよいですか?
- - アップデート - -
BOOL Cgraph_on_dlgboxDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
if ( m_bMyDraw )
return TRUE;
else
return CDialogEx::OnEraseBkgnd(pDC);
}
この関数は、先ほど説明したチュートリアルでこのように行われて以来、このように作成されています
------ UPDATE 2 ---------- return TRUE; と入力した場合。上記の関数の本体では、ちらつきが消えたように見えますが、出力は次のようになります
。ダイアログ ボックスの背景は、Visual Studio ウィンドウの内容を取得したようです。これを防ぐにはどうすればよいですか?