3

背景としてビットマップを使用している Windows XP で所有者が描画したボタンで、ビットマップが正しく表示されないという断続的な問題が発生しています。ボタンの背景に使用されるビットマップ イメージに同じビットマップ ファイルを使用している複数のボタンを含むウィンドウが表示され、ほとんどのボタンが正しく表示されます。小さいサイズ。

アプリケーションを終了してから再起動すると、ボタンのアイコンが正しく表示されないという同じ動作が見られる場合がありますが、以前と同じボタンである場合とそうでない場合があります。また、ボタン上のアイコンが正しく表示されないというこの動作は、常に見られるわけではありません。表示される場合と表示されない場合があります。ボタンのアイコンをロードすると、それを保持するだけなので、ボタンが正しく表示されないと、常に正しく表示されなくなります。

GetObject()デバッガーを使用して、最終的に、関数が呼び出されたときにビットマップ サイズに対して返されるデータが正しくないことがあることがわかりました。たとえば、あるケースでは、ビットマップが 75x75 ピクセルで、返されるサイズGetObject()が 13x13 でした。このサイズはビットマップの描画の一部として使用されるため、表示される背景はボタン ウィンドウの小さな装飾になります。

実際のソース領域は次のとおりです。

if (!hBitmapFocus) {
    CString iconPath;
    iconPath.Format(ICON_FILES_DIR_FORMAT, m_Icon);
    hBitmapFocus = (HBITMAP)LoadImage(NULL, iconPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
if (hBitmapFocus) {
    BITMAP   bitmap;
    int iNoBytes = GetObject(hBitmapFocus, sizeof(BITMAP), &bitmap);
    if (iNoBytes < 1) {
        char xBuff[128];
        sprintf (xBuff, "GetObject() failed. GetLastError = %d", GetLastError ());
        NHPOS_ASSERT_TEXT((iNoBytes > 0), xBuff);
    }
    cxSource = bitmap.bmWidth;
    cySource = bitmap.bmHeight;
    //Bitmaps cannot be drawn directly to the screen so a 
    //compatible memory DC is created to draw to, then the image is 
    //transfered to the screen
    CDC hdcMem;
    hdcMem.CreateCompatibleDC(pDC);

    HGDIOBJ  hpOldObject = hdcMem.SelectObject(hBitmapFocus);

    int xPos;
    int yPos;

    //The Horizontal and Vertical Alignment
    //For Images
    //Are set in the Layout Manager
    //the proper attribute will have to be checked against
    //for now the Image is centered on the button

    //Horizontal Alignment
    if(btnAttributes.horIconAlignment == IconAlignmentHLeft){//Image to left
        xPos = 2;
    }else if(btnAttributes.horIconAlignment == IconAlignmentHRight){//Image to right
       xPos = myRect.right - cxSource - 5;
    }else {//Horizontal center
       xPos = ((myRect.right - cxSource) / 2) - 1;
    }

    //Vertical Alignment
    if(btnAttributes.vertIconAlignment == IconAlignmentVTop){//Image to top
        yPos = 2;
    }else if(btnAttributes.vertIconAlignment == IconAlignmentVBottom){//Image to bottom
        yPos = myRect.bottom - cySource - 5;
    }else{//Vertical Center
        yPos = ((myRect.bottom - cySource) / 2) - 1;
    }

    pDC->BitBlt(xPos, yPos, cxSource, cySource, &hdcMem, 0, 0, SRCCOPY);

    hdcMem.SelectObject(hpOldObject);
}

デバッガーを使用すると、iconPath文字列が正しく、ビットマップが読み込まれてhBitmapFocusNULL ではないことがわかります。GetObject()次に、 への呼び出しが行われ、返される値iNoBytesが 24 に等しいことがわかります。値が正しく表示されるボタンの場合は正しいですがbitmap.bmWidth、値が表示されないボタンのbitmap.bmHeight場合、値が小さすぎて、描画時にサイズが正しくありません。ビットマップ。

変数は、クラス ヘッダーで次のように定義されます。

HBITMAP hBitmapFocus;

これに関する調査の一環として、このスタック オーバーフローの質問を見つけました。GetObject は奇妙なサイズを返します。ここに何らかのアライメントの問題があるかどうか疑問に思っています。

bitmap呼び出しで使用される変数は、GetObject()何らかのアライメント境界上にある必要がありますか? データの一部にパックを使用している間、pragmaディレクティブを使用して、1 バイト境界でパックする必要があるインクルード ファイル内の特定の構造体を含むコードの特定の部分のみを指定しています。

4

1 に答える 1

0

パレット情報を含むビットマップをロードする方法については、このMicrosoftKBをお読みください。良い例もあります。

補足::: DeleteObject(hBitmapFocus)を呼び出すコードのどこにも表示されません。GDIオブジェクトがすぐになくなる可能性があるため、これを呼び出すことは非常に重要です。

プログラムがGDIリソースを使い果たしていないことを確認するには、Windowsタスクマネージャーを使用することをお勧めします。タスクマネージャーに[GDIオブジェクト]列を追加するだけで、アプリ内でオブジェクトの数が絶えず増加しているわけではなく、他のプログラムと同様に期待される範囲内にとどまっていることを確認できます。

于 2012-12-17T22:16:46.640 に答える