VC++のドラッグ中の図の描画方法について

このQ&Aのポイント
  • VC++のドラッグ中における図の描画方法について質問です。
  • 具体的には、マウスドラッグしながら長方形を描画する際に、既存の図形を消去する方法について理解できません。
  • SetROP2とブラシの併用によって既存の図形を消去できる理由や、ブラシの復元によって内部が真っ白になる理由、塗りつぶしの順序について教えてください。
回答を見る
  • ベストアンサー

VC++ ドラッグしながらの図の描画に関して

描画に関して質問があります。 アクセサリのペイントツールのようにマウスドラッグしながら長方形を描画させたいのですが、 ドラッグの際に既に描画してあった長方形を消去する方法が理解できません。 具体的には以下のような方法です。 // ドラッグ中の描画処理 SetROP2( hDC, R2_NOT ); // 前景モードを変更 hPen = CreatePen( PS_DOT, 1, RGB(0, 55, 0) ); // 黒い点線のペンを作成 hBrush = (HBRUSH)GetStockObject( NULL_BRUSH ); // 空のブラシを取得 SelectObject( hDC, hPen ); // 作成したペンを使用するように設定 SelectObject( hDC, hBrush ); // 取得したブラシを使用するように設定 Rectangle( hDC, start.x, start.y, old_end.x, old_end.y ); // 四角形を描画 SetROP2とブラシは共に塗りつぶしを指定するものですが、これらを併用することによって何故既存の図形を消去していくことができるのかわかりません。 疑問になったのでブラシに関する記述を消去し実行してみると長方形内部の色が反転されましたが、これは理解できます。 しかし、これにブラシに関する記述を復元させることにより、なぜ内部が真っ白になるのかがわかりません。 また、塗りつぶしはSetROP2とブラシのどちらが先に行うのでしょうか?お手数ですが回答よろしくお願いします。

  • rew
  • お礼率79% (50/63)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

 こんにちは。質問意図は理解できました。  DrawFocusRect()を使った方が合理的かもしれません。このAPIは同じ四角形座標に向かって2回呼び出すと元に戻ります。  ペンやブラシなどでも似た様な事は出来ますが、以前の四角形を残さないようにする為バックバッファなどが必要になり、SetROP2()でチョッとやそっといじくっただけでは、実現するのは難しいかもしれません。  この手の事は説明するのが難しいので以下を参考にしてみてください。   //マウスをドラッグしてDrawFocusRect()を使って領域を描きます。 //キャプチャーされているかどうか static bool s_bCapture = false; //四角形の領域を記録する static RECT s_rcFocus = {0}; //変数を初期化する static void Init() { s_bCapture = false; ::ZeroMemory(&s_rcFocus, sizeof(s_rcFocus)); } //lParamからPOINTに変換 static const POINT PointFromLParam(LPARAM lParam) { const POINT pt = {(short)LOWORD(lParam), (short)HIWORD(lParam)}; return pt; } int CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CANCELMODE : { //何かのトラブルでキャプチャーが解除されてしまった場合は変数を初期化する ::Init(); return TRUE; } case WM_LBUTTONDOWN : { //キャプチャーされているので引き返す if(s_bCapture) return TRUE; //キャプチャーする ::SetCapture(hDlg); s_bCapture = true; //最初の座標を記憶する const POINT pt = ::PointFromLParam(lParam); s_rcFocus.left = pt.x; s_rcFocus.top = pt.y; return TRUE; } case WM_LBUTTONUP : { //キャプチャーを解く ::ReleaseCapture(); //変数を初期化する ::Init(); return TRUE; } case WM_MOUSEMOVE : { //キャプチャーされていないので引き返す if(!s_bCapture) return TRUE; //新しいマウス座標を取る const POINT ptNew = ::PointFromLParam(lParam); //新しい四角形領域 const RECT rcNew = {s_rcFocus.left, s_rcFocus.top, ptNew.x, ptNew.y}; //古い四角形と新しい四角形の領域を比較する if( rcNew.left == s_rcFocus.left && rcNew.top == s_rcFocus.top && rcNew.right == s_rcFocus.right && rcNew.bottom == s_rcFocus.bottom) return TRUE; //デバイスコンテキストを取る HDC hDC = ::GetDC(hDlg); //古い四角形を消す ::DrawFocusRect(hDC, &s_rcFocus); //新しい四角形サイズに更新 s_rcFocus = rcNew; //新しい四角形を描画 ::DrawFocusRect(hDC, &s_rcFocus); //デバイスコンテキストを戻す ::ReleaseDC(hDlg, hDC); return TRUE; } default : ; } return 0; }

rew
質問者

お礼

ありがとうございました。解決できました。

関連するQ&A

  • 【WinAPI】 四角形の色を選択して描画

    環境:VisualStudio2005、WinXP 目的:閉じた図形の内部の色を指定の色で塗りつぶしたい 現在 // 四角形を描画(Polygonバージョン) int x1 = 0, y1 = 0, x2 = 100, y2 = 100; POINT p[ 4 ]; p[ 0 ].x = x1, p[ 0 ].y = y1; p[ 1 ].x = x2, p[ 1 ].y = y1; p[ 2 ].x = x2, p[ 2 ].y = y2; p[ 3 ].x = x1, p[ 3 ].y = y2; Polygon( hdc, p, 4 ); や // 四角形を描画(Rectangleバージョン) Rectangle( x1, y1, x2, y2 ); などで四角形を描画するプログラムを作っています。 そしてこれに色を指定したいのですが、枠の部分に関しては HPEN hPen = CreatePen( PS_SOLID, 1/*線の厚さ*/, RGB(255,0,0) ); SelectObject( hdc , hPen ); // この後に四角形を描画 を指定することで色が変わりました。 しかし四角形の内側の部分の色に関しての色の指定方法が分かりません。 SelectObject(hdc , GetStockObject( GRAY_BRUSH ) ); でGRAY_BRUSH、BLACK_BLUSHなど数種類の指定ができるというのを調べましたが、 これだと好きな色を指定できません。 閉じた図形の内部の色を好きな色で塗りつぶす方法は無いのでしょうか・・?

  • Rectangleで、リソースが解放されない

    只今 Borland C コンパイラ 5.5.1 においてプログラムを書いているのですが、(C言語) 仕様なのかどうなのか、ある処理でウィンドウのサイズを ぐりぐり動かしつづけるとリソースが減っていって フリーズしていしまいます。使用しているWindowsは98SEです。 そのプログラムは、ウィンドウプロシージャにおいて、 case WM_PAINT:  hdc = BeginPaint(hWnd,&ps);    hPen = CreatePen(PS_SOLID, 0, RGB(255,0,0));  hOldPen = (HPEN)SelectObject(hdc, hPen);  hBrush = CreateSolidBrush(RGB(0,255,0));  Rectangle(hdc, 10,10,100,100);  DeleteObject(hPen);  SelectObject(hdc, hOldPen);  DeleteObject(hBrush);  DeleteObject(hOldPen);    EndPaint(hWnd,&ps);  break; という風に、Rectangle関数で画面に四角形を描画しているのですが、どうも上記の処理を何度も行うことにより リソースが解放されずに大量に消費されてしまいます。 C言語においてはまだ少しわかるほどのレベルで、 殆どの関数の意味を今だに理解していなくプログラムの 文法になにかしらの間違いがあるかもしれませんが、 ご指摘いただければ幸いです。

  • 重なり z-index

    HWND hrs;//プロト hrs = CreateWindow( ... というのがあって  wsprintf(mojibuf,"色付けが実行された");  SetWindowText(hrs,cbuf);  hDC = BeginPaint(hWnd, &ps);  hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));//枠色  SelectObject(hDC, hPen);  hBrush = CreateSolidBrush(RGB(0, 255, 0));//中色  SelectObject(hDC, hBrush);  Rectangle(hDC, 10, 90, 150, 100);  DeleteObject(hBrush);  EndPaint(hWnd, &ps); これで、hWnd に文字と四角を表示しました。 表示位置を重なるようにしたら、ソースの後に書いた方の 四角が文字に隠れてしまいました。 四角を文字の上になるようにして、重なった部分の文字は 四角で消されるようにするにはどうしたらいいんですか?

  • Windows API ペンを作るタイミング

    ゲームのプログラミングをしています。 テキストのサンプルプログラムではペンやブラシをWM_CREATEの中で hPen[1] = CreatePen(PS_SOLID, 2, RGB(50,70,0));    :    : のような感じで生成して WM_PAINT内でSelectObject(hdc, hPen[i]); として使っているのですが 自分のプログラムはPaintという関数を使っています。 その場合Paint(~)にそれらの配列を渡す形で良いのでしょうか? 一応今はそれで動いてます。 ただ描画の処理は1つの関数にまとめると書いてあったので Paint内で生成&削除をした方がよいのかとも思いまして・・・ どっちが一般的なのか、どういう場合はどうすればいいのかっていうのが 経験がなくて全然わからないので教えて欲しいです。 一応落ち物ゲームやシューティングゲームを想定してます。

  • 描画バッファーのオーバーフローの管理について

    環境:プログラムの開発環境はWindows XP SP2でVC++6.0です。 現象: Pen,Brush描画処理を下記の単位で行っています。 //myPen,mybush set myPen.CreatePen(PS_SOLID, 1, mycolor); pOldPen=pDC->SelectObject(&myPen); mybrush.CreateSolidBrush(mycolor); pOldbrush=pDC->SelectObject(&mybrush); // //myPen,mybush draw // //myPen,mybush delete pDC->SelectObject(pOldPen); myPen.DeleteObject(); pDC->SelectObject(pOldbrush); mybrush.DeleteObject();  上記単位で色々なタイルを作り図を描いています。 マウスドラッグに追随させこの図を回転や移動させるため再描画 させると、システムのバッファオーバーフローが起き、プログラムが 異常終了してしまいます。タイマーにより再描画速度を遅らせると 異常終了は起きません。 質問:何かPen,Brushによるシステムバッファの使用状況を管理する    関数または方法はありませんでしょうか?

  • SelectObjectの戻り値

    SDKについて勉強中なのですSelectObject関数についてどうしても引っかかることがあります。 とあるサイトにはSelectObjectは、前に結びついていたハンドルを戻り値とすると書いてありました。 http://kerochan.no-ip.com/vcsdk/letsprog/chap14.htm に書いてある例で、 ******************************************* hBit = CreateCompatibleBitmap(hdc,ScrnSize.right,ScrnSize.bottom); SelectObject(memdc,hBit); SelectObject(memdc,hBit);*****(1) hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); hDefBrush = SelectObject(memdc,hBrush);*****(2) PatBlt(memdc,0,0,ScrnSize.right,ScrnSize.bottom,PATCOPY); ReleaseDC(hwnd,hdc); SelectObject(memdc,hDefBrush);*****(3) DeleteObject((HGDIOBJ)hBrush); ****************************************** となっているのですが、(1)でmemdcと関連付けたビットマップハンドル(hBit)は、(2)でmemdcに新たにブラシハンドル(hBrush)と関連付けることによって切り離されてしまうのでしょうか?それとも切り離されるものは種類単位なのでしょうか?ブラシハンドルを関連付けたら前のブラシハンドルが返って来るとか・・ SelectObject関数の戻り値に付いていまいちはっきりしていないのでわかる方がいらしたらよろしくお願いします。

  • なぜCreateHatchBushの設定が途中で喪失するのか

    いつもお世話になります。 縦縞の四角形を表示するプログラムですが、ある一定の四角形を描画すると四角形の中の縦縞がなくなり、白色になります。 原因が分かりません。アドバイスをお願い致します。 (四角形をマウスドラッグ中に小さくすると黒い線がたくさんでてきますが、これはアプリケーションの仕様です) プロシージャソースは以下の通り。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; static POINT start, end; static bool push; switch(msg) { case WM_CREATE: push = false; break; case WM_LBUTTONDOWN: start.x = LOWORD(lParam); start.y = HIWORD(lParam); push = true; break; case WM_MOUSEMOVE: if(push){ end.x = LOWORD(lParam); end.y = HIWORD(lParam); InvalidateRect(hWnd, NULL, FALSE); } break; case WM_LBUTTONUP: end.x = LOWORD(lParam); end.y = HIWORD(lParam); push = false; InvalidateRect(hWnd, NULL, FALSE); break; case WM_PAINT: HBRUSH hBrush; hDC = BeginPaint(hWnd, &ps); hBrush = CreateHatchBrush(HS_VERTICAL, RGB(255, 0, 0)); SelectObject(hDC, hBrush); Rectangle(hDC, start.x, start.y, end.x, end.y); DeleteObject(hBrush); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } よろしくお願い致します。

  • VC++2010 で線形の描画についてですが・・

    VC++2010 で線形の描画についてまた質問なんですが、以下のように記述すると線ができなく、 点だけが動くプログラムになりました。解決方法がわからないのでよろしくお願いします。 今回のプロジェクトの目的はある機器からデータを取ってきて(1msごとに)それを1msごとに 直線として出力するプロジェクトです 電圧                    ↑          ________ ↑         |          |________→→ ーーーーーーーー  →→時間 ↑↑↑ このような線を出力しなければならないです。 以下がソースになっています。 使用環境VC++2010 MFC test10000Dlg.cpp ちなみにm_lineXとm_lineYはメンバー変数です(double型) ボタンがクリックされたときのイベント SetTimer(0, 1, NULL); void Ctest10000Dlg::OnTimer(UINT_PTR nIDEvent) { UpdateData(); after_datay = sam_data; m_xvEditX = m_lineX; m_xvEditSamd = m_lineY; m_xvEditSami = sam_i++; if(sam_i%200==0) { m_lineY -= 5; sam_i = 0; } m_lineX++; UpdateWindow(); Invalidate(FALSE); } void Ctest10000Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 描画のデバイス コンテキスト SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // クライアントの四角形領域内の中央 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; // アイコンの描画 dc.DrawIcon(x, y, m_hIcon); } else { //****************************************************************************************************** CRect rect_dlg; GetClientRect(&rect_dlg); CBrush br_black(RGB(0,0,0)); //各色ペン CPen pen_black(PS_SOLID,1,RGB(0,0,0)); CPen pen_gray(PS_DOT,1,RGB(128,128,128)); CPen pen_blue(PS_SOLID,1,RGB(0,0,255)); CPen pen_white(PS_SOLID,1,RGB(255,255,255)); int max_y=1; if(int(m_sin+m_cos+1.0)>max_y) max_y=int(m_sin+m_cos)+1; CDC* pDC=m_pict.GetDC(); //PictureControlの大きさ取得 CRect rect; m_pict.GetClientRect(&rect); //元のブラシをoldbrに保持 CBrush* oldbr=pDC->SelectObject(&br_black); //元のペンをoldpenに保持 CPen* oldpen=pDC->SelectObject(&pen_black); //(1)背景描画(ブラシ白、ペン黒) pDC->Rectangle(&rect); //(2)中心線(黒、実線) pDC->SelectObject(&pen_blue); pDC->MoveTo(10,rect.Height()-10); pDC->LineTo(10,10); pDC->MoveTo(10,rect.Height()-10); pDC->LineTo(rect.Width()-10,rect.Height()-10); pDC->SelectObject(&pen_white); pDC->MoveTo(m_lineX,m_lineY_after); pDC->LineTo(m_lineX+1,m_lineY); pDC->SelectObject(oldbr); pDC->SelectObject(oldpen); m_lineY_after = m_lineY; UpdateData(FALSE); CDialog::OnPaint(); } } ではよろしくお願いします

  • Windowsプログラミング 画面描画 ちらつき

    SetDIBitsToDevice関数を使って画面に描画をした後、LineTo関数やEllipse関数を使って その画面上に線や丸を表示させる処理をしているのですが、描画処理を一度にできていないためか ちらつきが発生してしまいます。 調べてみるとビットマップのマルチバッファリングなどが解決策にあるのですが、 私は一次元配列で画素値を格納していてビットマップに情報は保持していないため よく解決策で使われているBITBLTが使えない状態です。 裏画面に描画しておいて、最終的に描画は一度だけにするという考えは分かるんですが、 これをSetDIBitsToDevice関数を用いてちらつきが発生しないようにできるんでしょうか? プログラムとしては画像の上に線と円をひたすら描画していくようなイメージをしています。 アドバイスお願いします! case WM_PAINT: hDC=BeginPaint(hParent,&ps); SetDIBitsToDevice( ps.hdc, 0, 0,// コピー先x,y座標 pimg -> bih.biWidth,// DIBの幅 pimg -> bih.biHeight,// DIBの高さ 0, 0,// DIBの座標 0,// 走査線 pimg -> bih.biHeight,/ 走査線数 pimg -> lpBmpData, (BITMAPINFO *)&( pimg -> bih),// BITMAPINFOにキャスト DIB_RGB_COLORS ); for(int i=0; i<number-1; i++){ if(i==0){  hPen1 = CreatePen(PS_SOLID, 1, RGB(255,0,0));  electObject(hDC,hPen1);  MoveToEx(hDC,Xs,Ys,NULL);  Ellipse(hDC,Xs-2,Ys-2,Xs+2,Ys+2); }else{  LineTo(hDC,Xe,Ye);  Ellipse(hDC,Xs-2,Ys-2,Xs+2,Ys+2); } }

  • CDC(LineTo)で描画した線を透過したい

    タイトルのままで恐縮です。 ソースは、以下のような感じです。 描画の所で線を描いているのですが、例えば、SetBkModeなどで、背景を透過(TRANSPARENT)等は、やった事があるのですが、文字そのものの透過がわかりません。透過率は適当で構いません。ご存知の方、ご教授願います。 宜しくお願い致します。 (中略) // 描画した線自体を透過させたいです。 CDC* dc; // 実際は、関数のパラメータです // ペンの作成 CPen Pen; CPen* pOldPen = NULL; if ( Pen.CreatePen( PS_SOLID, 2, color ) == FALSE ) { return false; } pOldPen = dc->SelectObject( &Pen ); // 描画(線を描く) // widht, height は関数パラメータ dc->MoveTo( x, y ); // この線を透過したい dc->LineTo( x + width, x + height ) ); dc->MoveTo( x + width, y ); // この線を透過したい dc->LineTo( x, y + height ); // ペンを元に戻す dc->SelectObject( pOldPen );