2

グラフィックにはwin32とgdi+でc++を使用しています。
WM_CREATEの外部、特にWM_TIMERメッセージでボタンを初期化すると、1つのフレームが描画された後、他に何も描画できなくなります。コードの抜粋は次のとおりです。

case WM_TIMER:
    RECT client;
    GetClientRect(hWnd, &client);
    client.bottom-=100; //The bottom hundred pixels are static after I draw the first frame, so I never update them
    if(starting==true)
    {
        starting=false;
        hdc = GetDC(hWnd);
        hdcBuf = CreateCompatibleDC(hdc);
        hdcMem = CreateCompatibleDC(hdcBuf);
        hbmBackBM = CreateCompatibleBitmap(hdc, client.right, client.bottom );
        hbmOldBackBM = (HBITMAP)SelectObject(hdcBuf, hbmBackBM);

        Graphics temp(hdc);
        SolidBrush yelloworange(Color(250,225,65));
        temp.FillRectangle(&yelloworange,0,client.bottom,client.right,100); //Fill the bottom with yellow
        buttons[0]=CreateWindow("button","makereg", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 630, 60, 20, hWnd, HMENU(IDB_MAKEREG), NULL, NULL);
        //buttons[1]=CreateWindow("button","destroyreg", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 670, 80, 20, hWnd, HMENU(IDB_MAKEREG+1), NULL, NULL);
    }
    Graphics g(hdcBuf);

最初の部分はダブルバッファリング用であり、インスタンス化する変数はグローバルです。WM_DESTROYのHDCとHBITMAPを削除します。startは、trueとしてインスタンス化されるグローバルブール値です。このWM_TIMERメッセージですべての描画を行います。ボタンが作成された2行だけをコメントアウトすると、すべてが正常に実行されます。それらを使用すると、このWM_TIMERに残っているものだけが描画され、次のWM_TIMERには描画されません。他のすべての描画コードはhdcBufまたはgに対して実行され、hdcBufはhdcにBitBltされます。

WM_CREATEでボタンを作成し、それをWM_TIMERで表示しようとしましたが、同じ問題が発生しました。WM_CREATEでウィンドウを作成して表示することはできません。そうしないと、下の100ピクセルを黄色で塗りつぶしたときにウィンドウが描画されてしまうためです。

コードの残りの部分をクラッシュさせることなく、WM_CREATEの外側とWM_PAINTの外側にボタンを作成して表示する方法はありますか?

編集:WM_TIMERで動作を停止するコードの一部を次に示します。

if(mousex!=uptomousex && mousey!=uptomousey && lbuttondown==true) // this code draws a rectangle between the point where the user begins holding the left mousebutton, and where the mouse is right now.
{
    if(uptomousex-mousex>0 && uptomousey-mousey>0)
        g.DrawRectangle(&(p[0]), mousex, mousey, uptomousex-mousex, uptomousey-mousey);
    else if(uptomousex-mousex<0 && uptomousey-mousey>0)
        g.DrawRectangle((&p[0]), uptomousex, mousey, mousex-uptomousex, uptomousey-mousey);
    else if(uptomousex-mousex>0 && uptomousey-mousey<0)
        g.DrawRectangle((&p[0]), mousex, uptomousey, uptomousex-mousex, mousey-uptomousey);
    else if(uptomousex-mousex<0 && uptomousey-mousey<0)
        g.DrawRectangle(&(p[0]), uptomousex, uptomousey, mousex-uptomousex, mousey-uptomousey);
}

いくつかのグローバル変数:

bool lbuttondown=false;
float mousex=0;
float mousey=0;
float uptomousex=0;
float uptomousey=0;

WndProcの他の場所...

case WM_LBUTTONDOWN:
    lbuttondown=true;
    mousex=(float)GET_X_LPARAM(lParam);
    mousey=(float)GET_Y_LPARAM(lParam);
    uptomousex=mousex;
    uptomousey=mousey;
    break;
case WM_MOUSEMOVE:
    if(mousex!=GET_X_LPARAM(lParam) && mousey!=GET_Y_LPARAM(lParam))
    {
        uptomousex=(float)GET_X_LPARAM(lParam);
        uptomousey=(float)GET_Y_LPARAM(lParam);
    }
    break;
4

2 に答える 2

1

タイマー呼び出しごとに少なくとも3つのデバイスコンテキストインスタンスを作成/取得しており、それらを削除/解放することはありません(少なくとも投稿したサンプルでは)。したがって、GDIシステム全体をクラッシュさせて終了するのは当然です。

GetDC()を呼び出すたびに、ReleaseDC()を呼び出す必要があります。

CreateCompatibleDC()を呼び出すたびに、DeleteObject()を呼び出す必要があります。

于 2012-12-24T15:42:50.990 に答える
0

なぜこれが発生するのかはわかりませんが、簡単なパッチを作成しました。独自のボタンクラスで、ここで共有します。

class button
{
public:
    int x;
    int y;
    int width;
    int height;
    string text;
    void (*func)(short);
    button(int px, int py, int w, int h, string txt, void (*f)(short))
    {
        x=px;
        y=py;
        width=w;
        height=h;
        text=txt;
        func=*f;
    }
};

次に、ボタン、allbuttonsのグローバルベクトルがあり、WM_LBUTTONUPメッセージで、allbuttonsをループして、クリックがボタン内にあるかどうかを確認し、クリックがあった場合はfuncを呼び出します。

そのシンプルで柔軟性があり、実際に機能します。ただし、グラフィックはもっと悪いので、好奇心から、Windowsボタンが機能しない理由を知りたいと思います。

于 2012-12-24T15:22:01.140 に答える