【发布时间】:2014-01-14 15:26:01
【问题描述】:
我有一个对话框,应该有一个自定义图像作为背景。
我没有将整个图像作为位图或任何其他格式,所以我必须从头开始绘制。
我用了一个icon(截图左下角的男性),一个EMF文件(下图截图),其余的由一个绿色渐变笔刷,浅灰色阴影笔刷组成, 和文本 - 均使用GDI 绘制。我的绘图结果如下所示(屏幕截图也包括控件):
当我将对话框向左移动,然后将其移回原来的位置时,我面临的问题就显现出来了。下一个屏幕截图的图片底部说明了正在发生的伪影:
对话框是无模式的,我在WM_CTLCOLORDIALOG中绘制整个图像,然后返回NULL_BRUSH。
这里是WM_CTLCOLORDIALOG处理程序的相关代码sn-p(注意我是直接在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 和WM_MOVE 返回InvalidateRect)。我在互联网上找不到任何可以帮助我的东西。
问题:如何更改我的代码以修复我面临的错误?
【问题讨论】:
-
为什么在 WM_CTLCOLORDLG 而不是 WM_PAINT 中绘制对话框?
-
地图有任何功能用途吗?你会在上面画更多的东西吗?如果不是,我建议不要花时间在不相关的东西上,并完全删除图像和背景图案。
-
@MarkRansom:我是初学者,不知道如何正确实现它。
-
@Dialectus:我的客户强制使用这种类型的背景——在我看来这只是一种“不必要的炫耀”,但我能做些什么......
-
只是查看了错误的图像,我怀疑您发送渐变填充坐标的方式存在错误。我可以想象,如果你得到的坐标顺序错误或计数错误,你最终可能会得到几个像你在那里看到的颜色的三角形。我会专注于那里并观察调试器中发生的情况。