• 締切済み

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); } }

みんなの回答

  • sygh
  • ベストアンサー率76% (42/55)
回答No.1

1. フロント バッファ(表画面、ウィンドウ自体やクライアント領域など)と互換性のある、バック バッファ(裏画面)用のビットマップを、フロント バッファのデバイス コンテキストを使ってCreateCompatibleBitmap()で作成し、ハンドル(HBITMAP hBackBufferBmp)を取得。 2. フロント バッファのデバイス コンテキストと互換性のある、バックバッファ用のデバイス コンテキストを、フロント バッファのデバイス コンテキストを使ってCreateCompatibleDC()で作成し、ハンドル(HDC hBackBufferDC)を取得。 3. HGDIOBJ hOldBackBufferBmp = SelectObject(hBackBufferDC, hBackBufferBmp); 4. hBackBufferDCに対してSetDIBitsToDevice(), MoveTo()/LineTo() などの描画関数を実行。 5. BitBlt(フロント バッファのデバイス コンテキスト, 0, 0, バック バッファ幅、バック バッファ高さ、hBackBufferDC, 0, 0, SRCCOPY); 6. SelectObject(hBackBufferDC, hOldBackBufferBmp); 7. DeleteDC(hBackBufferDC); 8. DeleteObject(hBackBufferBmp); 上記において、1 と 8 の処理は描画時に毎回行なうのではなく、ウィンドウ作成時やウィンドウ リサイズ時に限定すると効率化できます。 なお、質問するときは環境(実行環境のOSバージョン、Visual C++などの処理系のバージョン)と言語(C限定か、C++もOKか)が明記されていないと、回答する側もサンプル コードを書きにくいです。

関連するQ&A

  • windowsのアプリケーションを作っているのですがどうにもうまくコン

    windowsのアプリケーションを作っているのですがどうにもうまくコンパイルできず困っています。 キャスト演算子かポインタ関係だと思うのですがいろいろ変えてみてもうまくいきませんでした。 私は朝までしかいられないため起きておられる方ですぐに答えられる方がいれば具体的にどうしたらできるようになるか答えていただけますでしょうか? 今日を逃したら大体、一ヶ月先に反応すると思うのでよろしくお願いします。 以下エラー部分です。 LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { HDC hdc,hdcWin; PAINTSTRUCT ps; int i,j; switch(iMsg){ case WM_CREATE: lpDIB=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(BITMAPINFO)+E*F); lI=(LPBITMAPINFO)lpDIB; for(i=0;i<F;i++){ alpPixel[i]=(LPDWORD)(lpDIB+sizeof(BITMAPINFO)+E*i); } lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =B; lI->bmiHeader.biHeight =-B; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; for(i=0;i<D;i++){ *(alpPixel[0]+i)=0x00ff0000; *(alpPixel[1]+i)=0x0000ff00; *(alpPixel[2]+i)=0x000000ff; *(alpPixel[3]+i)=0x0000ffff; *(alpPixel[4]+i)=0x00ffffff; } hdc=GetDC(hwnd); hBMP=CreateCompatibleBitmap(hdcWin,C,C); hdcBMP=CreateCompatibleDC(hdc); hOldBMP=(HBITMAP)SelectObject(hdcBMP,hBMP); for(i=0;i<A;i++){ for(j=0;j<A;j++){ StretchDIBits(hdcBMP,j*B,i*B,B,B, 0,0,B,B,alpPixel[map[j+i*A]], lI,DIB_RGB_COLORS,SRCCOPY); } } ZeroMemory(&biInfo,sizeof(BITMAPINFO)); lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =C; lI->bmiHeader.biHeight =-C; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; ○ hBMP2=CreateDIBSection(hdc,&biInfo,DIB_RGB_COLORS,(LPVOID)(&lpPixel),NULL,0); //エラーはここ hdcBMP2=CreateCompatibleDC(hdc); hOldBMP2=(HBITMAP)SelectObject(hdcBMP2,hBMP2); ReleaseDC(hwnd,hdc); X=0; Y=1; return 0; case WM_DESTROY: ~中略~ } return DefWindowProc(hwnd,iMsg,wParam,lParam); }

  • 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のアプリケーションを作っているのですがどうにもうまくコン

    windowsのアプリケーションを作っているのですがどうにもうまくコンパイルできず困っています。 一ヶ月前に同じ質問をしたのですが具体的にどうすればいいのかわからなかったのでもう一度質問させていただきます。 キャスト演算子かポインタ関係だと思うのですがいろいろ変えてみてもうまくいきませんでした。 具体的にどうしたらできるようになるか答えていただけますでしょうか? 私の都合により、一ヶ月先に反応すると思うのでよろしくお願いします。 以下エラー部分です。 LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam) { HDC hdc,hdcWin; PAINTSTRUCT ps; int i,j; switch(iMsg){ case WM_CREATE: lpDIB=(LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(BITMAPINFO)+E*F); lI=(LPBITMAPINFO)lpDIB; for(i=0;i<F;i++){ alpPixel[i]=(LPDWORD)(lpDIB+sizeof(BITMAPINFO)+E*i); } lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =B; lI->bmiHeader.biHeight =-B; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; for(i=0;i<D;i++){ *(alpPixel[0]+i)=0x00ff0000; *(alpPixel[1]+i)=0x0000ff00; *(alpPixel[2]+i)=0x000000ff; *(alpPixel[3]+i)=0x0000ffff; *(alpPixel[4]+i)=0x00ffffff; } hdc=GetDC(hwnd); hBMP=CreateCompatibleBitmap(hdcWin,C,C); hdcBMP=CreateCompatibleDC(hdc); hOldBMP=(HBITMAP)SelectObject(hdcBMP,hBMP); for(i=0;i<A;i++){ for(j=0;j<A;j++){ StretchDIBits(hdcBMP,j*B,i*B,B,B, 0,0,B,B,alpPixel[map[j+i*A]], lI,DIB_RGB_COLORS,SRCCOPY); } } ZeroMemory(&biInfo,sizeof(BITMAPINFO)); lI->bmiHeader.biSize =sizeof(BITMAPINFOHEADER); lI->bmiHeader.biWidth =C; lI->bmiHeader.biHeight =-C; lI->bmiHeader.biPlanes =1; lI->bmiHeader.biBitCount =B; lI->bmiHeader.biCompression =BI_RGB; ○ hBMP2=CreateDIBSection(hdc,&biInfo,DIB_RGB_COLORS,(LPVOID)(&lpPixel),NULL,0); //エラーはここ hdcBMP2=CreateCompatibleDC(hdc); hOldBMP2=(HBITMAP)SelectObject(hdcBMP2,hBMP2); ReleaseDC(hwnd,hdc); X=0; Y=1; return 0; case WM_DESTROY: ~中略~ } return DefWindowProc(hwnd,iMsg,wParam,lParam); } エラー E2034 169: 'void *' 型は 'void * *' 型に変換できない(関数 __stdcall WndProc(HWND__ *,unsigned int,unsigned int,long) ) エラー E2340 169: 4 番目のパラメータは void * * 型として定義されているので void * 型は渡せない(関数 __stdcall WndProc(HWND__ *,unsigned int,unsigned int,long) ) エラーの部分はこんな感じでした。

  • SetDIBitsToDeviceで88x31のpngを

    表示しようとして int SetDIBitsToDevice( HDC hdc, int XDest,←0 int YDest,←0 DWORD dwWidth,←88 DWORD dwHeight,←31 int XSrc,←0 int YSrc,←0と31でトライ UINT uStartScan,←0 UINT cScanLines,←31 CONST VOID *lpvBits,←読み込んだpngのfufferポイ CONST BITMAPINFO *lpbmi,←&bmpInfo UINT fuColorUse←DIB_RGB_COLORS ); としました。ただし BITMAPINFO bmpInfoは bmpInfo.bmiHeader.biSize=40; bmpInfo.bmiHeader.biWidth=88; bmpInfo.bmiHeader.biHeight=31; bmpInfo.bmiHeader.biPlanes=1; bmpInfo.bmiHeader.biBitCount=0; bmpInfo.bmiHeader.biCompression=BI_PNG; bmpInfo.bmiHeader.biSizeImage=pngのbufferのsize; bmpInfo.bmiHeader.biXPelsPerMeter=0; bmpInfo.bmiHeader.biYPelsPerMeter=0; bmpInfo.bmiHeader.biClrUsed=0; bmpInfo.bmiHeader.biClrImportant=0; と定義しました。 (実際にdivファイルを表示できていたプログラムの関連部分の書き換え) が、絵がでません。 どの設定に問題があるのでしょうか?

  • 読み込んだBMPデータの行方

    参考書を元にBMPを読み込み、 BYTE*型にデータを移して、画像処理や転送に利用できるようにしたいのですが、 どこに画像データの実体が有るのかがよくわかりません・・。 ---------- static LPBYTE lpDIB = NULL; static LPBITMAPINFO lpbiInfo; static LPDWORD lpPixel; LPBYTE lpBMP; LPBITMAPINFOHEADER lpbiBMPInfo; LPBYTE lpBMPPixel; BYTE* ppp; static int iWidth, iHeight, iLength; int iFileSize; DWORD dwOffset; int i, j; HANDLE fhBMP; DWORD dwRead; HDC hdc; PAINTSTRUCT ps; /*BMP取得*/ //ファイルオープン fhBMP = CreateFile("test.bmp", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fhBMP == INVALID_HANDLE_VALUE) { MessageBox(NULL, "test.bmpが見つかりません。", "エラー", MB_OK); return 0; } //ファイルサイズ取得 iFileSize = GetFileSize(fhBMP, NULL); //ファイル読み込みバッファ確保 lpBMP = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, iFileSize); //ファイル読み込み ReadFile(fhBMP, lpBMP, iFileSize, &dwRead, NULL); //ファイルを閉じる CloseHandle(fhBMP); //BMP内のBITMAPINFO取得 lpbiBMPInfo = (LPBITMAPINFOHEADER) (lpBMP + sizeof(BITMAPFILEHEADER)); //先頭からピクセル列までのオフセット取得 dwOffset = *(LPDWORD)(lpBMP + 10); //BMP内ピクセル列の先頭アドレス計算 lpBMPPixel = lpBMP + dwOffset; //ビットマップの大きさ取得 iWidth = lpbiBMPInfo->biWidth; iHeight = lpbiBMPInfo->biHeight; //BMPピクセル列の1ラインの長さを計算 if (iWidth % 4 == 0) { iLength = iWidth * 3; } else { iLength = iWidth * 3 + (4 - (iWidth * 3) % 4); } //DIB用バッファを確保 lpDIB = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFO) + iWidth * iHeight * 4); //DIB用ポインタ分配 lpbiInfo = (LPBITMAPINFO)lpDIB; lpPixel = (LPDWORD)(lpDIB + sizeof(BITMAPINFO)); //BITMAPINFO設定 lpbiInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbiInfo->bmiHeader.biWidth = iWidth; lpbiInfo->bmiHeader.biHeight = iHeight; lpbiInfo->bmiHeader.biPlanes = 1; lpbiInfo->bmiHeader.biBitCount = 32; lpbiInfo->bmiHeader.biCompression = BI_RGB; //BMP内のピクセル列を32ビット化してコピー for (i = 0;i < iHeight;i++) for (j = 0;j < iWidth; j++) CopyMemory(lpPixel + j + i * iWidth, lpBMPPixel + j * 3 + i * iLength, 3); //ファイル読み込みバッファ解放 HeapFree(GetProcessHeap(), 0, lpBMP); /*描画*/ hdc = BeginPaint(hWnd, &ps); //DIBをウインドウのDCに描画 StretchDIBits(hdc, 0, 0, iWidth, iHeight, 0, 0, iWidth, iHeight, lpPixel, lpbiInfo, DIB_RGB_COLORS,SRCCOPY); EndPaint(hWnd, &ps); ---------- 描画部分のStretchDIBits()を調べて lpPixelに格納されているように思えたのですが、これはただのDWORDですし。 lpBMPPixelだとしても、描画では全く使われていないのが不可解で。 なぜこう(描画にDWORD)なっているのでしょうか? どこに画像データが有るのでしょうか?

  • 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言語においてはまだ少しわかるほどのレベルで、 殆どの関数の意味を今だに理解していなくプログラムの 文法になにかしらの間違いがあるかもしれませんが、 ご指摘いただければ幸いです。

  • SetDIBitsToDeviceでpngを

    描画する際に int SetDIBitsToDevice( HDC hdc, // デバイスコンテキストのハンドル int XDest, // 転送先長方形の左上隅の x 座標 int YDest, // 転送先長方形の左上隅の y 座標 DWORD dwWidth, // 転送元長方形の幅 DWORD dwHeight, // 転送元長方形の高さ int XSrc, // 転送元長方形の左下隅の x 座標 int YSrc, // 転送元長方形の左下隅の y 座標 UINT uStartScan, // 配列内の最初の走査行 UINT cScanLines, // 走査行の数 CONST VOID *lpvBits, // DIB ビットからなる配列 CONST BITMAPINFO *lpbmi, // ビットマップ情報 UINT fuColorUse // RGB 値またはパレットインデックス ); を指定しないといけないのですが png画像の縦幅と png画像の横幅と png画像のビットマップ情報が分からないとこの関数の引数を指定できません。 どのようにそれらの情報を知ればよいのでしょうか?

  • OnPaint() とOnDraw()の違いについて

    OnPaint内に記述した下記コードでビットマップが描画されますが、OnDraw内だと描画されません。 どうしてなのか教えてください。 お願いします。 void CAbcView::OnPaint() { HBITMAP myDIB; // ビットマップのハンドル HBITMAP oldDIB; HDC hDC; // デバイスコンテキストのハンドル HDC hCompatiDC; // メモリデバイスコンテキスト PAINTSTRUCT ps; // クライアント領域の描画に使う情報を保持 if(!m_BmpInfo) return; hDC = ::GetDC(m_hWnd);//これでもOK ::BeginPaint(m_hWnd,&ps); hCompatiDC = ::CreateCompatibleDC(hDC);//hDC); myDIB = ::CreateDIBitmap(hDC,&m_BmpInfo->bmiHeader, CBM_INIT,m_BmpImage,m_BmpInfo,DIB_RGB_COLORS); oldDIB=(HBITMAP)::SelectObject(hCompatiDC,myDIB); BitBlt(hDC,5,25,m_BmpInfo->bmiHeader.biWidth, m_BmpInfo->bmiHeader.biHeight,hCompatiDC,0,0,SRCCOPY); 略 } 環境 WIN98 VC++6.0 MFC にて

  • ビットマップ画像の表示

    どうしても正確に動作をしないので、問題点をご指摘していただきたいです。 開発環境はVisual Studio 2005です 24bitのビットマップ画像を読み込み、新しいwindowを作成して表示するプログラムを作成しています。 しかし、読み込んでから新しいWindowは作成されるのですが、どうしても画像が表示されません。 私が気にしている部分は、画像を読み込んでから新しく作成するWindowのプロシージャにおいて、WM_PAINTメッセージで行うべき処理です。 以下にプロシージャを載せます。 LRESULT CALLBACK WndProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam ){ PAINTSTRUCT ps; switch( Message ){ case WM_PAINT: BeginPaint( hWnd, &ps ); SetDIBitsToDevice( ps.hdc, 0, 0, pDib->biWidth, pDib->biHeight, 0, 0, 0, pDib->biHeight, pBitmap, (BITMAPINFO *)pDib, DIB_RGB_COLORS ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, Message, wParam, lParam ); } return 0; } pDibは PBITMAPINFOHEADER のグローバル変数です。 そしてpDibへ情報を格納するとき、 bitmapSize = bmFileHdr.bfSize - sizeof(BITMAPFILEHEADER);   pDib = ( BITMAPINFOHEADER * )malloc( bitmapSize ); と領域を確保し、   fread( pDib, bitmapSize, 1, fp ) というように格納しました。 このときの fp は BITMAPFILEHEADER の分だけ進んでいます。 bmFileHdr は BITMAPFILEHEADERです。 つまりBITMAPFILEHEADER以降の情報を全て格納しました。 また SetDIBitsToDevice での題10引数の pBitmap は    pBitmap = (BYTE *)(pDib) + bmFileHdr.bfOffBits - sizeof(BITMAPFILEHEADER); のように求めました。先ほども記述しましたが pDib には BITMAPFILEHEADER 以降の情報を全て格納したので、pDibからヘッダ部分のみポインタを進めました。 やはり WM_PAINTメッセージの部分で、SetDIBitsToDevice関数だけではなく、そのほかに設定することがあるのでしょうか?

  • 点の描画について(win32API)

    win32APIでウィンドウに点を描画するプログラムを作ったのですが、SetPixel関数で点を描画しようとすると、特定のx座標に点が描画されません。線は普通に描画されるのですが・・・。 /*ソース*/ #include <windows.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT Msg, WPARAM wp, LPARAM lp) { static HDC hdc; static PAINTSTRUCT ps; switch(Msg) { case WM_PAINT: //【ここです!】 hdc = BeginPaint(hwnd, &ps); MoveToEx(hdc , 0 , 300 , NULL); //比較のため線を引く準備 LineTo(hdc,1200,300); //比較のため線を引く for( int j = 1000; j > 0 ; j-- )SetPixel( hdc, j, 100, RGB(0,200,100) ) ; for( int j = 1000; j > 0 ; j-- )SetPixel( hdc, j, 200, RGB(0,200,100) ) ; //ここで点を描画 EndPaint(hwnd, &ps); return 0; case WM_DESTROY: //終了処理 PostQuitMessage(0); return 0; } return DefWindowProc( hwnd, Msg, wp, lp ); } //↓ごく普通のWinMainです。無視してください。 int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow ) { HWND hwnd; MSG msg; WNDCLASS winc; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL , IDI_APPLICATION); winc.hCursor = LoadCursor(NULL , IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("KITTY"); if (!RegisterClass(&winc)) return -1; hwnd = CreateWindow( TEXT("KITTY") , TEXT("Kitty on your lap") , WS_OVERLAPPEDWINDOW | WS_VISIBLE , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , NULL , NULL , hInstance , NULL ); if (hwnd == NULL) return -1; while( GetMessage(&msg , NULL , 0 , 0) ) DispatchMessage(&msg); return msg.wParam; } 解決策を模索するもうまくいかず・・・どうか回答よろしくお願いします。

専門家に質問してみよう