我有一个对话框,它应该有一个自定义图像作为背景。
我没有位图或任何其他格式的整个图像,所以我必须从头开始绘制。
我使用了一个icon
(截图左下角的男性),一个EMF
文件(下面截图中的 map ),剩下的包括绿色渐变画笔、浅灰色阴影画笔和文本的组合 - 所有这些都是使用 GDI
绘制的。我的绘图结果如下所示(屏幕截图也包含控件):
当我将对话框向左 移动然后将其移回其原始位置时,我遇到的问题就出现了。下一个屏幕截图的图片底部说明了发生的工件:
对话框是无模式对话框,我在WM_CTLCOLORDIALOG
中绘制整个图像,之后返回NULL_BRUSH
。
这里是WM_CTLCOLORDIALOG
处理程序的相关代码片段(请注意,我直接在DC上绘制,没有双缓冲。原因是这个是一个快速测试代码,很快就出错了):
case WM_CTLCOLORDLG:
{
RECT rect; // dialog's client rectangle
GetClientRect( hwnd, &rect );
// ligh gray brush for hatched brush
HBRUSH hbPozadina = CreateSolidBrush( RGB( 242, 242, 242 ) );
FillRect( (HDC)wParam, &rect, hbPozadina );
// cleanup
DeleteObject( hbPozadina );
// draw grid "manualy"
LOGBRUSH lbPozadina;
HGDIOBJ hPenPozadina = NULL, hOldPenPozadina;
lbPozadina.lbColor = RGB( 255, 255, 255 );
lbPozadina.lbHatch = 0;
lbPozadina.lbStyle = BS_SOLID;
hPenPozadina = ExtCreatePen( PS_COSMETIC | PS_SOLID, 1, &lbPozadina, 0, NULL);
hOldPenPozadina = SelectObject((HDC)wParam, hPenPozadina);
// draw vertical lines
for( int i = rect.left + 12; i< rect.right; i += 12)
{
MoveToEx((HDC)wParam, i, rect.top, NULL );
LineTo((HDC)wParam, i, rect.bottom - rect.top + 1 );
}
// draw horizontal lines
for( int i = rect.top + 12; i< rect.bottom; i += 12)
{
MoveToEx((HDC)wParam, rect.left, i, NULL );
LineTo((HDC)wParam, rect.right - rect.left + 1, i );
}
//clean up
SelectObject((HDC)wParam, hOldPenPozadina);
DeleteObject(hPenPozadina);
// draw metafile of the map
HENHMETAFILE hemf = GetEnhMetaFile( L".\\resources\\KartaDlg.emf" );
ENHMETAHEADER emh;
GetEnhMetaFileHeader( hemf, sizeof(emh), &emh );
// remove the "status bar" from the calculation
RECT r;
r.top = rect.top;
r.bottom = rect.bottom - 30;
r.left = rect.left;
r.right = rect.right;
// calculate rescaled metafile
UINT o_height = emh.rclFrame.bottom - emh.rclFrame.top,
o_width = emh.rclFrame.right - emh.rclFrame.left;
float scale = 0.5;
scale = (float)( r.right - r.left ) / o_width;
if( (float)( r.bottom - r.top ) / o_height < scale )
scale = (float)( r.bottom - r.top ) / o_height;
int marginX = ( r.right - r.left ) - (int)( o_width * scale );
int marginY = ( r.bottom - r.top ) - (int)( o_height * scale );
marginX /= 2;
marginY /= 2;
r.left = r.left + marginX;
r.right = r.right - marginX;
r.top = r.top + marginY;
r.bottom = r.bottom - marginY;
// Draw the picture.
PlayEnhMetaFile( (HDC)wParam, hemf, &r );
// Release the metafile handle.
DeleteEnhMetaFile(hemf);
// this function draws green gradient and icon
drawFooter( (HDC)wParam, rect,
RGB( 0x48, 0xAC, 0xC6), RGB( 0x31, 0x83, 0x99 ) );
//========= draw right text in status bar =============//
SetBkMode( (HDC)wParam, TRANSPARENT );
SIZE sBaner; // needed for proper positioning
HFONT hf, hfOld;
long lfHeight;
lfHeight = -MulDiv( 8, GetDeviceCaps( (HDC)wParam, LOGPIXELSY), 72 );
hf = CreateFont( lfHeight, 0, 0, 0, FW_BOLD, TRUE,
0, 0, 0, 0, 0, 0, 0, L"Arial Black" );
hfOld = (HFONT)SelectObject( (HDC)wParam, hf ); // needed for proper cleanup
GetTextExtentPoint32( (HDC)wParam,
L"ЦЕНТАР ЗА ОБНОВЉИВЕ ВОДНЕ ЕНЕРГЕТСКЕ РЕСУРСЕ",
wcslen(L"ЦЕНТАР ЗА ОБНОВЉИВЕ ВОДНЕ ЕНЕРГЕТСКЕ РЕСУРСЕ"),
&sBaner );
// position it properly
r.bottom = rect.bottom;
r.right = rect.left + sBaner.cx + 30;
r.left = rect.left + 30;
r.top = rect.bottom - rect.top - 30;
// draw it
DrawTextEx( (HDC)wParam,
L"РУДАРСКО ГЕОЛОШКИ ФАКУЛТЕТ\nЦЕНТАР ЗА ОБНОВЉИВЕ ВОДНЕ ЕНЕРГЕТСКЕ РЕСУРСЕ",
wcslen(L"РУДАРСКО ГЕОЛОШКИ ФАКУЛТЕТ\nЦЕНТАР ЗА ОБНОВЉИВЕ ВОДНЕ ЕНЕРГЕТСКЕ РЕСУРСЕ"),
&r, DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_WORDBREAK, 0 );
SelectObject( (HDC)wParam, hfOld ); // proper cleanup
DeleteObject( hf );
//============== right text in the status bar ==================//
lfHeight = -MulDiv( 10, GetDeviceCaps( (HDC)wParam, LOGPIXELSY), 72 );
hf = CreateFont( lfHeight, 0, 0, 0, FW_BOLD, TRUE,
0, 0, 0, 0, 0, 0, 0, L"Arial" );
hfOld = (HFONT)SelectObject( (HDC)wParam, hf ); // needed for proper cleanup
GetTextExtentPoint32( (HDC)wParam,
L" Дејан Миленић & Ана Врањеш © 2013 сва права задржана",
wcslen(L" Дејан Миленић & Ана Врањеш © 2013 сва права задржана"),
&sBaner );
// position it properly
r.bottom = rect.bottom;
r.right = rect.right - 10;
r.left = rect.right - rect.left - sBaner.cx - 10;
r.top = rect.bottom - rect.top - sBaner.cy;
// draw it
DrawTextEx( (HDC)wParam,
L" Дејан Миленић & Ана Врањеш © 2013 сва права задржана",
wcslen(L" Дејан Миленић & Ана Врањеш © 2013 сва права задржана"),
&r, DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_WORDBREAK | DT_NOPREFIX, 0 );
// perform proper cleanup
SelectObject( (HDC)wParam, hfOld );
DeleteObject(hf);
}
return (INT_PTR)GetStockObject(NULL_BRUSH);
为了使这个更加完整,我提交了 drawFooter
函数及其辅助函数:
// Fills triangle with gradient brush
void GradientTriangle( HDC MemDC,
LONG x1, LONG y1, LONG x2, LONG y2, LONG x3, LONG y3,
COLORREF top, COLORREF bottom )
{
TRIVERTEX vertex[3];
vertex[0].x = x1;
vertex[0].y = y1;
vertex[0].Red = GetRValue(bottom) << 8;
vertex[0].Green = GetGValue(bottom) << 8;
vertex[0].Blue = GetBValue(bottom) << 8;
vertex[0].Alpha = 0x0000;
vertex[1].x = x2;
vertex[1].y = y2;
vertex[1].Red = GetRValue(top) << 8;
vertex[1].Green = GetGValue(top) << 8;
vertex[1].Blue = GetBValue(top) << 8;
vertex[1].Alpha = 0x0000;
vertex[2].x = x3;
vertex[2].y = y3;
vertex[2].Red = GetRValue(bottom) << 8;
vertex[2].Green = GetGValue(bottom) << 8;
vertex[2].Blue = GetBValue(bottom) << 8;
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);
}
// draw the window's footer ( "status bar" )
void drawFooter( HDC MemDC, RECT r, COLORREF top, COLORREF bottom )
{
// bottom triangle
GradientTriangle( MemDC,
r.right, r.bottom,
( r.right - r.left ) / 2,
r.bottom - r.top - 15,
r.left,
r.bottom,
top, bottom );
// upper triangle
GradientTriangle( MemDC,
r.right, r.bottom - r.top - 30,
( r.right - r.left ) / 2,
r.bottom - r.top - 15,
r.left,
r.bottom - r.top - 30,
top, bottom );
// left triangle
GradientTriangle( MemDC,
r.left, r.bottom,
( r.right - r.left ) / 2,
r.bottom - r.top - 15,
r.left,
r.bottom - r.top - 30,
top, bottom );
// right triangle
GradientTriangle( MemDC,
r.right,
r.bottom - r.top - 30,
( r.right - r.left ) / 2,
r.bottom - r.top - 15,
r.right,
r.bottom,
top, bottom );
// draw icon
DrawIconEx( MemDC, r.left, r.bottom - r.top - 30,
hiAdmin, // a global variable for icon
30, 30, NULL, NULL, DI_NORMAL );
}
视觉样式已启用 - 这可能很重要,我不知道。
我没有处理 WM_ERASEBKGND
也没有处理 WM_SIZE
或 WM_MOVE
(对话框不能调整大小。)。我已经尝试过但没有帮助(为 WM_ERASEBKGND
返回 TRUE
,为 WM_SIZE
和 返回
)。我在互联网上找不到任何可以帮助我的东西。InvalidateRect
WM_MOVE
问题:如何更改我的代码以修复我遇到的错误?
最佳答案
您正在滥用 WM_CTLCOLORDLG
消息。它旨在提供一种简单的方法来更改对话框的背景颜色,而不是自定义绘制它。
您应该在那里返回 NULL_BRUSH
,或者甚至完全忽略该消息,并在 WM_ERASEBKGND
中绘制背景。
或者甚至更好,您可以忽略 WM_ERASEBKGND
并在 WM_PAINT
中进行绘画,就像任何其他窗口一样。
更新:在下面的一些评论之后,问题似乎是调用 GradientFill()
三角形时顶点的顺序。即:
- 顶点顺时针排列:绘制三角形。
- 顶点逆时针排列:不绘制三角形。
或者也许是相反的方式,我永远也说不准......
无论如何,仍然存在一个谜,即为什么有时它无论顺序如何都有效,而有时它只适用于特定的顺序。此外,这是否记录在任何地方?
我猜测这可能是驱动程序/2D 加速问题...所以这将取决于 DC 是在显示器上还是在内存中,但这很难说。
关于c++ - 对话框不正确地重绘其背景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21117252/