API GradientFill не работает должным образом

ВВЕДЕНИЕ И СООТВЕТСТВУЮЩАЯ ИНФОРМАЦИЯ:

Я хочу создать статический элемент управления с градиентным фоном.

Я хочу сделать это следующим образом:

Создайте градиент на фоне основного окна, а затем поместите прозрачный статический элемент управления поверх этого фона.

Для этого я создал 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так что это не подведет.

ВОПРОС:

Как это исправить?

Заранее спасибо.

С уважением.

0

Решение

Я думаю, что просто ваши вычисления для вершин неверны:

        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 розыгрыши.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]