GradientFill API tidak berfungsi sebagaimana mestinya

PENDAHULUAN DAN INFORMASI RELEVAN:

Saya ingin membuat kontrol statis dengan latar belakang gradien.

Saya ingin melakukannya dengan cara berikut:

Buat gradien di latar belakang jendela utama, lalu tempatkan kontrol statis transparan di atas latar belakang tersebut.

Untuk melakukan itu, saya telah membuat variabel RECT di WM_PAINT handler yang memposisikan gradien pada posisi di mana kontrol statis seharusnya berada.

Selain itu, saya mencoba menggunakan buffering ganda untuk menghindari kedipan (Saya juga telah menangani WM_ERASEBKGND, menghapus flag CS_VREDRAW dan CS_HREDRAW dari kelas jendela).

Saya juga telah menangani pesan WM_SIZE untuk membuat jendela tidak valid, dan memposisikan ulang kontrol statis dengan benar.

Di WM_CTLCOLORSTATIC handler saya, saya telah mengembalikan NULL_BRUSH.

Saya telah membuat aplikasi demo untuk menggambarkan hal ini, melalui wizard aplikasi di Visual Studio.

Saya bekerja pada Windows XP, menggunakan Win32 API murni dan C++.

Di bawah ini saya akan mengirimkan kode yang dimodifikasi untuk WM_PAINT, dan cuplikan untuk penangan lain yang tercantum di atas:

    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;

MASALAH:

Saat saya menggunakan GradientFill API di WM_PAINT handler, saya mendapatkan persegi panjang yang lebih besar di layar dari yang seharusnya.

Gambar di bawah mengilustrasikan hasil ini:

masukkan deskripsi gambar di sini

Jika saya mencoba mengisi persegi panjang yang sama dengan kuas padat, semuanya berfungsi dengan baik.

Gambar di bawah mengilustrasikan hasil ini:

masukkan deskripsi gambar di sini

UPAYA SAYA UNTUK MEMECAHKAN MASALAH:

Saya telah menempatkan breakpoint di tempat koordinat persegi panjang ditetapkan dan tidak melihat adanya masalah.

Selain itu, GradientFill mengembalikan TRUE, sehingga tidak gagal.

PERTANYAAN:

Bagaimana cara memperbaikinya?

Terima kasih sebelumnya.

Salam.


person AlwaysLearningNewStuff    schedule 11.11.2013    source sumber


Jawaban (1)


Saya pikir itu hanya karena perhitungan Anda untuk simpulnya salah:

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

Haruskah rect.top + ( rect.bottom - rect.top ) / 2 atau yang serupa? Atau bahkan hanya masing-masing rect.bottom dan rect.top?

Itu tergantung apa yang ingin Anda capai, tetapi menurut saya, saat ini bukan itu yang Anda inginkan. Anda perlu menggunakan rect.bottom dan rect.top untuk mendapatkan bentuk yang sama dengan gambar FillRect yang Anda komentari.

person Jonathan Potter    schedule 11.11.2013
comment
Mr.Potter, saya mencoba membuat gradien yang memiliki warna lebih terang di bagian atas dan bawah persegi panjang, dan warna lebih gelap di tengah. Saya berpikir untuk mengisi bagian atas persegi panjang dengan kuas gradien yang lebih terang di bagian atas, dan lebih cerah di bagian bawah. Kemudian, bagian bawah persegi panjang akan diisi dengan kuas yang lebih terang di bagian bawah, dan lebih gelap di bagian atas. Dengan mengisi persegi panjang dengan 2 kuas tersebut, saya akan mendapatkan efek kuas gradien tunggal, yang terang di bagian atas dan bawah, dan gelap di tengah. Solusi Anda berhasil, jadi beri +1 dari saya. Terima kasih. - person AlwaysLearningNewStuff; 11.11.2013