GradientFill API ไม่ทำงานอย่างที่ควรจะเป็น

บทนำและข้อมูลที่เกี่ยวข้อง:

ฉันต้องการสร้างการควบคุมแบบคงที่พร้อมพื้นหลังแบบไล่ระดับสี

ฉันต้องการทำด้วยวิธีต่อไปนี้:

สร้างการไล่ระดับสีที่พื้นหลังของหน้าต่างหลัก จากนั้นวางการควบคุมคงที่แบบโปร่งใสไว้ด้านบนของพื้นหลังนั้น

ในการทำเช่นนั้น ฉันได้สร้างตัวแปร RECT ในตัวจัดการ WM_PAINT ซึ่งวางตำแหน่งการไล่ระดับสีในตำแหน่งที่ควรควบคุมแบบคงที่

นอกจากนี้ฉันพยายามใช้การบัฟเฟอร์สองครั้งเพื่อหลีกเลี่ยงการกะพริบ (ฉันได้จัดการ WM_ERASEBKGND แล้วลบแฟล็ก CS_VREDRAW และ CS_HREDRAW ออกจากคลาสหน้าต่างด้วย)

ฉันยังจัดการข้อความ WM_SIZE เพื่อทำให้หน้าต่างใช้ไม่ได้ และเพื่อเปลี่ยนตำแหน่งการควบคุมแบบคงที่อย่างเหมาะสม

ในตัวจัดการ WM_CTLCOLORSTATIC ของฉัน ฉันได้ส่งคืน NULL_BRUSH แล้ว

ฉันได้สร้างแอปพลิเคชันสาธิตเพื่อแสดงสิ่งนี้ผ่านตัวช่วยสร้างแอปพลิเคชันใน Visual Studio

ฉันทำงานบน Windows XP โดยใช้ Win32 API และ C++ ล้วนๆ

ต่อไปนี้ ฉันจะส่งโค้ดที่แก้ไขแล้วสำหรับ WM_PAINT และตัวอย่างข้อมูลสำหรับตัวจัดการอื่นๆ ที่ระบุไว้ข้างต้น:

    case WM_CREATE:
         {
             // get rectangle dimensions of the main window

             RECT rec;
             GetClientRect( hWnd, &rec );

             /******* main window's static control ******/

             HWND StaticControl = CreateWindowEx( 0, L"Static", L"", 
                                     WS_VISIBLE | WS_CHILD | SS_NOTIFY,
                                     ( 3 * ( rec.right - rec.left ) / 4 - 340 ) / 3,
                                     120 + ( rec.bottom - rec.top - 450 ) / 3, 
                                     150, 150, hWnd, (HMENU)4000, hInst, 0);
         }
         return (LRESULT)0;

    case WM_SIZE:
        {
             RECT rec; // main window's client rectangle

             GetClientRect( hWnd, &rec ); 

             SetWindowPos( GetDlgItem( hWnd, 4000 ),
                           NULL,
                           ( 3  * ( rec.right - rec.left ) / 4 - 340 ) / 3, 
                           120 + ( rec.bottom - rec.top - 450 ) / 3, 150, 150,
                           SWP_NOZORDER );

            InvalidateRect( hWnd, NULL, FALSE); 
        }
        return (LRESULT)0;

    case WM_ERASEBKGND:
        return (LRESULT)1;

    case WM_CTLCOLORSTATIC:
        return (LRESULT)( (HBRUSH)GetStockObject(NULL_BRUSH) );

    case WM_PAINT:
        {
            hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code here...

            RECT r; // rectangle for main window's client area

            GetClientRect( hWnd, &r);

            HDC MemDC = CreateCompatibleDC(hdc); // back buffer

            // compatible bitmap for MemDC

            HBITMAP bmp = CreateCompatibleBitmap( hdc,
                                                  r.right - r.left, 
                                                  r.bottom - r.top ),
                    oldBmp = (HBITMAP)SelectObject( MemDC, bmp ); // needed for cleanup

            /***** draw a reference header at the top of the window *******/

            // position it properly at the top

            RECT rect;

            rect.left = r.left;
            rect.top = r.top;
            rect.right = r.right;
            rect.bottom = 120;

            FillRect( MemDC, &rect, (HBRUSH)GetStockObject(LTGRAY_BRUSH) );

            /**** main window's gradient background *******/

            //============ down triangle =========//

            TRIVERTEX vertex[3];

            vertex[0].x     = r.right;
            vertex[0].y     = r.bottom - r.top;
            vertex[0].Red   = 0xDB00;
            vertex[0].Green = 0xE500;
            vertex[0].Blue  = 0xF100;
            vertex[0].Alpha = 0x0000;

            vertex[1].x     = r.left;
            vertex[1].y     = r.bottom - r.top;
            vertex[1].Red   = 0x9500;
            vertex[1].Green = 0xB300;
            vertex[1].Blue  = 0xD700;
            vertex[1].Alpha = 0x0000;

            vertex[2].x     = r.left;
            vertex[2].y     = r.top + 120; 
            vertex[2].Red   = 0xDB00;
            vertex[2].Green = 0xE500;
            vertex[2].Blue  = 0xF100;
            vertex[2].Alpha = 0x0000;

            // Create a GRADIENT_TRIANGLE structure that
            // references the TRIVERTEX vertices.

            GRADIENT_TRIANGLE gTriangle;

            gTriangle.Vertex1 = 0;
            gTriangle.Vertex2 = 1;
            gTriangle.Vertex3 = 2;

            // Draw a shaded triangle.

            GradientFill( MemDC, vertex, 3, &gTriangle, 1, GRADIENT_FILL_TRIANGLE);

            //=============== upper triangle =================//

            TRIVERTEX vertex1[3];

            vertex1[0].x     = r.right;
            vertex1[0].y     = r.bottom - r.top;
            vertex1[0].Red   = 0xDB00;
            vertex1[0].Green = 0xE500;
            vertex1[0].Blue  = 0xF100;
            vertex1[0].Alpha = 0x0000;

            vertex1[1].x     = r.right;
            vertex1[1].y     = r.top + 120;
            vertex1[1].Red   = 0x9500;
            vertex1[1].Green = 0xB300;
            vertex1[1].Blue  = 0xD700;
            vertex1[1].Alpha = 0x0000;

            vertex1[2].x     = r.left;
            vertex1[2].y     = r.top + 120; 
            vertex1[2].Red   = 0xDB00;
            vertex1[2].Green = 0xE500;
            vertex1[2].Blue  = 0xF100;
            vertex1[2].Alpha = 0x0000;

            // Draw a shaded triangle.

            GradientFill( MemDC, vertex1, 3, &gTriangle, 1, GRADIENT_FILL_TRIANGLE);

            //**** draw background of the static control ****//

            //position it properly 

            rect.left = ( 3  * ( r.right - r.left ) / 4 - 340 ) / 3;
            rect.top = 120 + ( r.bottom - r.top - 450 ) / 3;
            rect.right = 150 + ( 3  * ( r.right - r.left ) / 4 - 340 ) / 3;
            rect.bottom = 270 + ( r.bottom - r.top - 450 ) / 3; // this one fails!!!

            //FillRect( MemDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH) );

            // vertexes for static's gradient color

            //================= top rectangle =====================//

            TRIVERTEX vertexS[2], vertex1S[2] ;

            vertexS[0].x     = rect.left;
            vertexS[0].y     = rect.top;
            vertexS[0].Red   = 0x9500;
            vertexS[0].Green = 0xB300;
            vertexS[0].Blue  = 0xD700;
            vertexS[0].Alpha = 0x0000;

            vertexS[1].x     = rect.right;
            vertexS[1].y     = ( rect.bottom - rect.top ) / 2; 
            vertexS[1].Red   = 0x4F00;
            vertexS[1].Green = 0x8B00;
            vertexS[1].Blue  = 0xBD00;
            vertexS[1].Alpha = 0x0000;

            //================== bottom rectangle ====================//

            vertex1S[0].x     = rect.left;
            vertex1S[0].y     = ( rect.bottom - rect.top ) / 2; 
            vertex1S[0].Red   = 0x4F00;
            vertex1S[0].Green = 0x8B00;
            vertex1S[0].Blue  = 0xBD00;
            vertex1S[0].Alpha = 0x0000;

            vertex1S[1].x     = rect.right;
            vertex1S[1].y     = rect.bottom;
            vertex1S[1].Red   = 0x9500;
            vertex1S[1].Green = 0xB300;
            vertex1S[1].Blue  = 0xD700;
            vertex1S[1].Alpha = 0x0000;

            // Create a GRADIENT_RECT structure that 
            // references the TRIVERTEX vertices.

            GRADIENT_RECT gRect;

            gRect.UpperLeft  = 0;
            gRect.LowerRight = 1;

            // Draw a shaded rectangle. 

            GradientFill( MemDC, vertexS, 2, &gRect, 1, GRADIENT_FILL_RECT_V );
            GradientFill( MemDC, vertex1S, 2, &gRect, 1, GRADIENT_FILL_RECT_V );

            /****** draw back buffer on the screen DC *****************/

            BitBlt( hdc, 0, 0, r.right - r.left, r.bottom - r.top,
                    MemDC, 0, 0, SRCCOPY );

            /************** cleanup *******************/

            SelectObject( MemDC, oldBmp );

            DeleteObject(bmp); // compatible bitmap for MemDC

            DeleteDC(MemDC);

            EndPaint(hWnd, &ps);
        }
        return (LRESULT)0;

ปัญหา:

เมื่อฉันใช้ GradientFill API ในตัวจัดการ WM_PAINT ฉันจะได้สี่เหลี่ยมบนหน้าจอที่ใหญ่กว่าที่ควรจะเป็น

รูปภาพด้านล่างแสดงผลลัพธ์นี้:

ป้อนคำอธิบายรูปภาพที่นี่

หากฉันพยายามเติมสี่เหลี่ยมเดียวกันด้วยแปรงทึบ ทุกอย่างทำงานได้ดี

รูปภาพด้านล่างแสดงผลลัพธ์นี้:

ป้อนคำอธิบายรูปภาพที่นี่

ความพยายามของฉันในการแก้ไขปัญหา:

ฉันวางเบรกพอยท์ไว้ที่ตำแหน่งที่กำหนดพิกัดของสี่เหลี่ยมผืนผ้าแล้วและไม่พบปัญหาใดๆ เลย

นอกจากนี้ GradientFill จะส่งกลับ TRUE ดังนั้นจึงไม่ล้มเหลว

คำถาม:

จะแก้ไขปัญหานี้ได้อย่างไร?

ขอบคุณล่วงหน้า.

ความนับถือ.


person AlwaysLearningNewStuff    schedule 11.11.2013    source แหล่งที่มา


คำตอบ (1)


ฉันคิดว่าเป็นเพียงการคำนวณจุดยอดของคุณผิด:

        vertexS[1].y     = ( rect.bottom - rect.top ) / 2; 
        /* .... */
        vertex1S[0].y     = ( rect.bottom - rect.top ) / 2;

พวกเขาควรจะเป็น rect.top + ( rect.bottom - rect.top ) / 2 หรืออะไรที่คล้ายกัน? หรือแม้แต่เพียง rect.bottom และ rect.top ตามลำดับ?

มันขึ้นอยู่กับสิ่งที่คุณพยายามทำให้สำเร็จ แต่อย่างใด ฉันคิดว่าตอนนี้ยังไม่ใช่สิ่งที่คุณต้องการ คุณจะต้องใช้ rect.bottom และ rect.top เพื่อให้ได้รูปทรงเดียวกับที่คุณวาดความคิดเห็นไว้ FillRect

person Jonathan Potter    schedule 11.11.2013
comment
คุณพอตเตอร์ ฉันกำลังพยายามสร้างการไล่ระดับสีที่มีสีอ่อนกว่าที่ด้านบนและด้านล่างของสี่เหลี่ยมผืนผ้า และมีสีเข้มกว่าตรงกลาง ฉันคิดว่าจะเติมครึ่งบนของสี่เหลี่ยมด้วยแปรงไล่ระดับสีที่ด้านบนสว่างกว่าและสว่างกว่าที่ด้านล่าง จากนั้นครึ่งล่างของสี่เหลี่ยมจะเต็มไปด้วยแปรงที่สว่างกว่าที่ด้านล่างและเข้มกว่าที่ด้านบน ด้วยการเติมแปรง 2 อันนั้นลงในสี่เหลี่ยมผืนผ้า ผมจะได้เอฟเฟกต์เหมือนแปรงไล่ระดับสีอันเดียว ซึ่งมีแสงที่ด้านบนและด้านล่าง และมืดตรงกลาง วิธีแก้ปัญหาของคุณใช้งานได้ +1 จากฉัน ขอบคุณ - person AlwaysLearningNewStuff; 11.11.2013