VC++のペイント処理で絵が消えてしまう問題を解決する方法

このQ&Aのポイント
  • VC++のマネージ形式でピクチャーボックスにMousDownした時にMouseMoveを使って、絵で落書きする際、元に戻すと絵が消えてしまう問題が発生しています。
  • SetPexelを使ってプログラムを処理し、pictureBoxにMousuDownして絵を書くと点状になる問題があります。
  • 最小化しても絵が消えず、スムーズにかける方法を知りたいです。
回答を見る
  • ベストアンサー

vc++のペイント処理。

VC++のマネージ形式でピクチャーボックスにMousDownした時にMouseMoveを使って、絵で落書きするんですが、デバックして絵を書いた後、Formを最小化した後、元に戻すと、絵を書いたのに、書いた絵が消えてます。この時の絵を書くときには、PenとGraphicと配列処理(<arry> Point)を使いました。 今度は、SetPexelを使ってプログラムをくんで、Bitmapとして処理したら、pictureBoxにMousuDownして絵を書くと、点みたいに書けてゆっくりMousuDownしてるときは、線をかけるんですが、早く書こうとすると点々みたいのでかけますし、最小化しても消えません。 前者の方法だとスムーズにかけるんですが、消えちゃいます。 後者の場合はゆっくり書けば何とか線は書けるんですがスムーズに書けません。 どうしたら、最小化しても消えずにスムーズにかけますか?? 書ける方法てあるんですか??

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

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

Bitmapにしても DrawPolygonで描画すればいいのですよ 直接描画の場合 grf = pictureBox1->CreateGraphics(); Bitmap描画の場合 grf = Graphics::FromImage( bmp ); といった具合に Graphicsオブジェクトの構築方法を変更します Bitmap描画の際MouseMoveやMouseDownから抜ける前に pictureBox1->Image = bmp; といった具合に描画したBitmapをピクチャーボックスに設定しましょう http://oshiete1.goo.ne.jp/qa4367456.html のコードの中のMouseDown > cap = true; > grf= pictureBox1->CreateGraphics(); > // > // > pen = gcnew Pen(color); > poi = gcnew cli::array<PointF>(2); > PointF pt = PointF(e->X, e->Y); > poi->SetValue(pt, 0); > poi->SetValue(pt, 1); > grf->DrawPolygon(pen, poi); > } の部分を cap = true; // Bitmapを構築 try {   // ビットマップbmpが作成済みかどうかのチェック   int n = bmp->Width; } catch( NullReferenceException^ ex ) {   // 未作成の場合は作成する   bmp = gcnew Bitmap( pictureBox1->Width, pictureBox1->Height ); } // grfの構築方法の変更 // grf = pictureBox1->CreateGraphics();   grf = Graphics::FromImage( bmp ); // //   pen = gcnew Pen(color);   poi = gcnew cli::array<PointF>(2);   PointF pt = PointF(e->X, e->Y);   poi->SetValue(pt, 0);   poi->SetValue(pt, 1);   grf->DrawPolygon(pen, poi);   // ピクチャーボックスの更新   pictureBox1->Image = bmp; } といった具合ですよ MouseMoveの最後にも   grf->DrawPolygon(pen, poi);   poi->SetValue(pt, 0);   // ピクチャーボックスの更新   pictureBox1->Image = bmp; を追加します

関連するQ&A

  • 兄弟のpictureboxは透過処理をするには?

    度々質問して申し訳ありません。 Controls.Addで親子にしたpicturebox はちゃんと透過処理してくれるのですが、 同じ親pictureboxの子供たち(兄弟)同士の透過処理が行われません。 違う設定が必要なのでしょうか? 教えていただけますか?よろしくお願いします。 文字数多くて載せられないので、重要であろう箇所のみです。スミマセン。 image = New Bitmap("c:\image.png")'透過部有 iconGraphics = Graphics.FromImage(image) Icon1 = New System.Windows.Forms.PictureBox iconGraphics.DrawImage(image, 0, 0, iconSize, iconSize) PictureBox1.Image = image Icon1.Location = New Point(8, 8) Icon1.Width = iconSize Icon1.Height = iconSize Icon1.BackColor = Color.Transparent PictureBox1.Controls.Add(Me.Icon1) Icon1.BringToFront() Icon1.Image = image

  • pictureBoxの画像の座標の色の出し方。

    VC++で、pictureBoxで表示した画像を適当な場所をクリックするとその座標とRGBの色あいが表示するプログラムなんですが、エラーはしなかったんですが、デバックして画像表示して適当にクリックしてもなにも表示されませんでした。 プログラムに間違えでもあるのかみてください。 private: System::Void pictureBox1_MouseDown(System::Object^sender, System::Windows::Forms::MouseEventArgs^ e) { String^fname = openFileDialog1->FileName; Bitmap^fun = gcnew Bitmap(fname); Point^ p = PointToClient( Point(e->X ,e->Y)); Color^col = fun->GetPixel(p->X,p->Y); label1->Text = String::Format("..{0}", fun->GetPixel(p->X,p->Y)); }

  • マウスで画像の移動(VB2010)

    FormにPanelを配置してそのなかにPicturBoxを配置しています。 エクスプローラから画像をドラッグアンドドロップして、マウスで画像を移動させようと考えています。 (Panelのサイズを250,250にして、1024*768ピクセルの画像の一部を窓から見ているような感じ) 下記のコードを書いたのですが、マウスを左クリックした状態のままマウスを移動させると、画像がちらつきます。 PictureBox1.Refresh()を入れて多少現象しましたが、根本的な問題の解決には至っておりません。 どなたか?詳しい方いらっしゃいましたら教えて頂けないでしょうか?宜しくお願いいたいます。 Private drawFlag As Boolean Private ptStart As Point Private ptEnd As Point Private Sub PictureBox1_DragEnter(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) _ Handles PictureBox1.DragEnter If e.Data.GetDataPresent(DataFormats.FileDrop) Then e.Effect = DragDropEffects.Copy Else e.Effect = DragDropEffects.None End If End Sub Private Sub PictureBox1_DragDrop(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DragEventArgs) _ Handles PictureBox1.DragDrop Dim strFileName As String() = CType(e.Data.GetData(DataFormats.FileDrop), String()) Dim fi As New System.IO.FileInfo(strFileName(0)) Dim MyBmp As Bitmap = System.Drawing.Image.FromFile(strFileName(0)) PictureBox1.Image = MyBmp End Sub Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize PictureBox1.AllowDrop = True drawFlag = False End Sub Private Sub PictureBox1_MouseMove(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles PictureBox1.MouseMove If drawFlag = False Then Exit Sub End If ptEnd = e.Location Dim ptMove As Point ptMove = ptEnd - ptStart Dim MyLocation As Point MyLocation = PictureBox1.Location + ptMove PictureBox1.Location = MyLocation PictureBox1.Refresh() ptStart = ptEnd End Sub Private Sub PictureBox1_MouseDown(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles PictureBox1.MouseDown If e.Button = Windows.Forms.MouseButtons.Left Then drawFlag = True ptStart.X = e.X ptStart.Y = e.Y End If End Sub Private Sub PictureBox1_MouseUp(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles PictureBox1.MouseUp drawFlag = False End Sub

  • 移動する線を描画したい(何と例えたらいいのか・・・)

    Microsoft Visual Studio.Netの2003でC#を使っています。 pictureBoxに描画する時に、マウスとともに移動できる線(1つ前に描画した線を消せる)を 引きたいと思ったのですが、何の関数を使えば良いか分かりません・・・ よくマウスの先端から縦横に線が出て、今いる座標が分かるような描画ソフトがありますよね、 あんな感じの線を描画したいです。 つまり線は見えるけども後ろの絵は消えてないというやつです。それでマウスが動いたら 縦横の線も移動します。 どういう方法があるのでしょうか?

  • OpenCVの透過処理

    VC 2010 C++/CLI + OpenCVで教えていただきたい事が有ります。 【教えていただきたい事】 ・pbPictureの画像を透過処理して表示 ※ 同じサイズの画像をアルファブレンドしたり、上面の画像の背景のみを透過するサンプルは見かけるのですが、   背面と異なるサイズの上面の画像全体を透過する、サンプルを見つけられませんでした。   (純粋に透過する機能がopenCVには無いとの事で、小細工が必要なのだと考えています) 【やりたいこと】 ・pbBackground(Picturebox)に背景となる画像を読込表示 ・pbPicture(Picturebox)に親フォームで作成したBMPの図形(画像)を半透明(透過率50%位)で重ねて表示 ・pbBackgroundのサイズは読込データ依存 ・pbPictureのサイズは親フォームで作成した図形依存   ※つまり、pbBackgroundとpbPictureは違うサイズ ・将来的には、マウス移動でpbPictureの位置、大きさ、台形補間をする予定 イメージとしては、下記URLのお化け屋敷の画像とほぼ同じ http://aidiary.hatenablog.com/entry/20061203/1251465083 ※実際は、背景が風景で、上書きする画像は建屋 【現状できているのは】 ・cvLoadImageで画像を読込してpbBackgroundに描画 ・親フォームで作成した図形を無加工でpbPictureに描画 【現状のソース】 System::Void PhotoRead_Click(System::Object^ sender, System::EventArgs^ e) { double BmpX,BmpY,XYRatio; double PhotoX,PhotoY; int PX,PY; System::Drawing::Point p; System::String^ filename; // pbBackgroundのディフォルトサイズは500×500 OpenFileDialog^ OpFile = gcnew OpenFileDialog(); // OpFile->DefaultExt = "jpg"; OpFile->Filter = "画像ファイル(*.jpg;*.png;*.bmp;*.gif)|*.jpg;*.png;*.bmp;*.gif"; if (OpFile->ShowDialog() == Windows::Forms::DialogResult::OK) { SuspendLayout(); filename = OpFile->FileName; // String^型をchar*に安全に変換 char* pStr = (char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi( filename ).ToPointer(); // ファイル読み込み IplImage* img = cvLoadImage( pStr ); if( img == 0 ){ return; } // Bitmapに直接img->imgDataを読ませると、エラーになるのでコピーデータを渡す IntPtr ip( new unsigned char[ img->widthStep * img->height ] ); memcpy( ip.ToPointer(), img->imageData, img->widthStep * img->height ); Bitmap^ bmp = gcnew Bitmap(img->width, img->height, img->widthStep, System::Drawing::Imaging::PixelFormat::Format24bppRgb, ip); // 読み込みデータは解放 cvReleaseImage( &img ); //ピクチャボックスをビットマップ画像サイズに合わせる BmpX = (double)bmp->Width; BmpY = (double)bmp->Height; PhotoX = 500; PhotoY = 500; p.X = 10; p.Y = 40; PX = 500; PY = 500; if (BmpX <= BmpY) { XYRatio = BmpY / BmpX; PX = (int)(PhotoX / XYRatio); p.X = 10 + (500 - PX) /2; } else { XYRatio = BmpX / BmpY; PY = (int)(PhotoY / XYRatio); p.Y = 40 + (500 - PY) /2; } PictureBox^ pbBackground=gcnew PictureBox; pbBackground->Location = p; // サイズ指定、従来はWidthとHeightを別々に定義していたが、Sizeを使用すると1行で済む pbBackground->Size=System::Drawing::Size(PX,PY); //ピクチャボックスのImageへ読込画像をセット pbBackground->SizeMode = PictureBoxSizeMode::StretchImage; pbBackground->Image = bmp; Controls->Add(pbBackground); // ピクチャーボックスのpbBackgroundを親としているので、相対座標は0にする BmpX = (double)PhotBMP->Width; BmpY = (double)PhotBMP->Height; PhotoX = pbBackground->Width; PhotoY = pbBackground->Height; GX = (int)(PX / 2 - 100) + p.X; GY = (int)(PY / 2 - 100) + p.Y; // PictureBoxのグラフィックエリアにBitmapを描画する。 PictureBox^ pbPicture=gcnew PictureBox; pbPicture->Parent = pbBackground; pbPicture->Location = System::Drawing::Point(GX, GY); pbPicture->Size = System::Drawing::Size(200, 200); pbPicture->SizeMode = PictureBoxSizeMode::StretchImage; // 上書きする画像をセット pbPicture->Image = PhotBMP; Controls->Add(pbPicture); // デバッグで見やすくするためにバックをどぎつい色に BackColor=Color::FromArgb(0xFF,0xFF,0x00,0x00); pbPicture->BringToFront(); pbCursor->BringToFront(); ResumeLayout(); } }

  • VB2005 コード記述作法

    VBのコード記述作法に自身がなく不安です。 CADのラバーラインのような感じです。 PictureBoxを置いてFormの上下左右にアンカーしてるだけです。 lineモードにXorがないので下記のようにしました。 今は、とりあえず動いてますが、<?>印部分をここに記述しても安定動作しますか? (メモリの無駄使いとか・CPUの負荷とか) 又Form1_Resizeで再描画してますが、Windowを最小化すると当然でしょうが PictureBox1.Image = New Bitmap(PictureBox1.Width, PictureBox1.Height) でエラーになります。 これを防ぐ方法を教えて下さい。 Public Class Form1 Private sx, sy, ex, ey As Integer Private flg As Boolean = False Private fg, bg As Graphics   '----<?>---- Private d(100, 4) As Integer Private po As Integer = 1 '-------------------------------- Private Sub PictureBox1_MouseDown(~~ If flg = False Then sx = e.X sy = e.Y ex = sx ey = sy flg = True fg = PictureBox1.CreateGraphics() '----<?>---- Else flg = False ex = e.X ey = e.Y PictureBox1.Refresh() fg.Dispose() '----<?>---- bg = Graphics.FromImage(PictureBox1.Image) '----<?>---- bg.DrawLine(Pens.Black, sx, sy, ex, ey) bg.Dispose() '----<?>---- PictureBox1.Refresh() d(po, 1) = sx d(po, 2) = sy d(po, 3) = ex d(po, 4) = ey po = po + 1 End If End Sub '-------------------------------- Private Sub PictureBox1_MouseMove(~~ If flg = True Then PictureBox1.Refresh() fg.DrawLine(Pens.Blue, sx, sy, e.X, e.Y) ex = e.X ey = e.Y End If End Sub '-------------------------------- Private Sub Form1_Resize(~~ Dim x As Integer PictureBox1.Image = New Bitmap(PictureBox1.Width, PictureBox1.Height) bg = Graphics.FromImage(PictureBox1.Image) ' ----<?>---- For x = 1 To po - 1 bg.DrawLine(Pens.Black, d(x, 1), d(x, 2), d(x, 3), d(x, 4)) Next bg.Dispose() ' ----<?>---- End Sub '-------------------------------- End Class

  • 手書きの絵をペジェ曲線で描いたような綺麗な絵にしたい

    手書きの絵をスキャンし、パソコンに取り込んだ後、 イラストレーターなどのペジェ曲線で描いたような綺麗な絵(線)にワンタッチでできる処理はありますか? よろしくおねがいします。

  • Bitmapのディスク容量

     以下、VBの記法で書きます。Windows10,.NETのGDI+を使用しています。  PixelFormat が Format32bppArgb のBitmapを作成し、描画処理が終わった後、Bitmap.Save(パス名)で保存します。  Bitmapは1250×1250(pixel)なので、そのディスク容量は、   1250×1250×4(byte)=6104 KB=6 MB くらいと思ってました。ところが保存してみると、60 KBくらい・・・。  読みだして表示するとちゃんと保存されてるので、これはこれであり難い事なのですが、どうして?、という質問です(^^;)。  PixelFormat が Format32bppArgb の場合は初期化時に、各pixelの(A,R,G,B) は (A,R,G,B)=(0,0,0,0)であり、例えばPictureBox の BackColor との兼ね合いで、(R,G,B)=(0,0,0)(黒)はDefaultで透過色になってるので、ディスク保存時には、pixel位置を表すIndex付きでpixel情報が圧縮されて保存されるのかしら?、などと想像したわけです。  たんに気になるので、どうなってるか知りたいだけです。ネットで検索してもBitmapの大きさは、画素数×4 byte という記事しか出てこないので・・・(^^;)。  関連する検索キーワードでも良いので、教えてもらえませんか。

  • MFCプログラミング

    MFCのダブルバッファリングを用いて画面を切り替えるプログラムを作ったのですが 画面がちらついてしまいます、どう修正すればよいか教えてください // CgraphView 描画 void CgraphView::OnDraw(CDC* pDC) { CgraphDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: この場所にネイティブ データ用の描画コードを追加します。 CRect myRect; GetClientRect(myRect); if(background_color == 0) pDC->FillSolidRect(myRect, RGB(255, 255, 255)); else if(background_color == 1) pDC->FillSolidRect(myRect, RGB(153, 204, 255)); else pDC->FillSolidRect(myRect, RGB(255, 153, 204)); //ダブルバッファに関するコード CRect rc; GetClientRect(&rc); bkDC.CreateCompatibleDC(pDC); bkBMP.CreateCompatibleBitmap(pDC, rc.right, rc.bottom); CBitmap Bitmap, *pOldBitmap; pOldBitmap = bkDC.SelectObject(&bkBMP); //これから、すべての描画は、裏画面bkDCにおいて行う bkDC.FillSolidRect(rc, RGB(255, 255, 255)); int x, y, sx, sy; if(draw_state == 0) { bkDC.SetTextColor(RGB(0, 0, 0)); bkDC.TextOut(400, 500, _T("Start")); sx = 128;//表示するビットマップの横の大きさ sy = 128;//表示するビットマップの縦の大きさ y = 300;//表示するビットマップの左上の頂点のy座標 x = 50; draw_school(x, y, sx, sy); x = 200; draw_health(x, y, sx, sy); x = 350; draw_environment(x, y, sx, sy); } else if(draw_state == 1) { CRect myRect; GetClientRect(myRect); pDC->FillSolidRect(myRect, RGB(255, 255, 255)); } //裏画面bkDCにおいて、すべての描画を行った後 //裏画面を表画面に送る pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); bkDC.SelectObject(pOldBitmap); //裏画面を消去 bkBMP.DeleteObject(); bkDC.DeleteDC(); void CgraphView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。 bitmap[0].LoadBitmap(IDB_BITMAP1); bitmap[1].LoadBitmap(IDB_BITMAP2); bitmap[2].LoadBitmap(IDB_BITMAP3); bitmap[3].LoadBitmap(IDB_BITMAP4); bitmap[4].LoadBitmap(IDB_BITMAP5); bitmap[5].LoadBitmap(IDB_BITMAP6); Bmp_ID = 0; //タイマーをスタート SetTimer(ID_BITMAP, TIMER_MS_BITMAP, NULL); //画面再描画のタイマーをスタートする SetTimer(ID_REDRAW, TIMER_MS_FPS, NULL); Bmp_ID = 0; } void CgraphView::OnTimer(UINT_PTR nIDEvent) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 if(nIDEvent == ID_BITMAP) Bmp_ID = (Bmp_ID+1) % 2; if(nIDEvent == ID_REDRAW) InvalidateRect(NULL, FALSE); CView::OnTimer(nIDEvent); } void CgraphView::OnDestroy() { CView::OnDestroy(); // TODO: ここにメッセージ ハンドラ コードを追加します。 KillTimer(ID_BITMAP); KillTimer(ID_REDRAW); } void CgraphView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 mouse_x = point.x; mouse_y = point.y; if(draw_state == 0) { if(mouse_x > 400 && mouse_y > 500) { draw_state = 1; } } CView::OnLButtonDown(nFlags, point); } BOOL CgraphView::OnEraseBkgnd(CDC* pDC) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 return TRUE; //return CView::OnEraseBkgnd(pDC); }

  • 配列を使ったビットマップクラス

    VC++を使ったフォームアプリケーションでビットマップなどの画像を表示させ、ピクセル処理を施せるプログラムを作りました。このプログラム上ではピクチャボックスを1つ用意していますが、今後もっと多くのピクチャボックスが必要になってきます。以下のプログラムではBitmapクラスのbmpをピクチャボックス1の画像に入れています。単純にBitmapクラスのbmpを増やせば(例:bmp1)、ピクチャボックスが増えても平気ですが、処理の関係上配列を使いたいと思っています。なので下に書いてあるプログラムのbmp->という部分をbmp[0]->というふうに変えたいと考えています。自分なりに調べて(1)、(2)の部分を変えればいいと思うのですがどうもうまくいきません。わかる方がいたらご教授ください、おねがいします。 #pragma once namespace bmp { using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; using namespace System::Text; using namespace System::Collections::Generic; /// <summary> /// Form1 の概要 /// /// 警告: このクラスの名前を変更する場合、このクラスが依存するすべての .resx ファイルに関連付けられた /// マネージ リソース コンパイラ ツールに対して 'Resource File Name' プロパティを /// 変更する必要があります。この変更を行わないと、 /// デザイナと、このフォームに関連付けられたローカライズ済みリソースとが、 /// 正しく相互に利用できなくなります。 /// </summary> public ref class Form1 : public System::Windows::Forms::Form { public: Form1(void) { InitializeComponent(); // //TODO: ここにコンストラクタ コードを追加します // bmp = nullptr; ……… (1) //Bitmap^ bmp[300]; }      //省略// #pragma endregion //private: array<Bitmap^>^ bmp = gcnew array<Bitmap^>(300); ……… (2) private: Bitmap^ bmp; private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { bmp = gcnew Bitmap("C:/Documents and Settings/Owner/デスクトップ/lena.bmp",true); pictureBox1->Image = bmp; } private: System::Void pictureBox1_Click(System::Object^ sender, System::EventArgs^ e) { /*bmp = gcnew Bitmap("C:/Documents and Settings/Owner/デスクトップ/lena.bmp",true);*/ int x,y; int w = bmp->Width; int h = bmp->Height; for(x = 0; x < w; x++){ for(y = 0; y < h; y++){ if(x < (w * 0.05) || y < (h * 0.05) || (y > (h - (h*0.05)))&&(y < h) || (x > (w - (w*0.05)))&&(x < w)){ Color pixelColor = bmp->GetPixel( x, y ); Color newColor = Color::FromArgb( 255, 0, 0 ); bmp->SetPixel( x, y, newColor ); } } } pictureBox1->Image = bmp; } private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { } }; }

専門家に質問してみよう