对话框不正确地重绘其背景 [英] Dialog box improperly repaints its background

查看:147
本文介绍了对话框不正确地重绘其背景的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对话框,应该有一个自定义图像作为背景。



我没有整个图像作为位图或任何其他格式,所以我



我使用图标(屏幕左下角的男性) ,一个 EMF 文件(屏幕截图下方的地图),其余部分由绿色渐变画笔,浅灰色阴影画笔和文本组成 - code> GDI 。我的绘图结果看起来像这样(屏幕截图包括控件):





当我将对话框向左移动然后将其移回其原始位置。在下一个屏幕截图中,图片底部显示了发生的工件:





对话框是无模式对话框, c $ c> WM_CTLCOLORDIALOG 之后返回 NULL_BRUSH



这里是相关的代码片段对于 WM_CTLCOLORDIALOG 处理程序(请注意,我直接在DC上绘制,没有双缓冲。原因是这是一个快速测试代码出错了很快):

  case WM_CTLCOLORDLG:
{
RECT rect; //对话框的客户矩形

GetClientRect(hwnd,& rect);

//用于阴影刷的浅灰色刷子

HBRUSH hbPozadina = CreateSolidBrush(RGB(242,242,242));

FillRect((HDC)wParam,& rect,hbPozadina);

//清除

DeleteObject(hbPozadina);

//绘制网格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);

//绘制垂直线

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);
}

//绘制水平线

for(int i = rect.top + 12; i {
MoveToEx((HDC)wParam,rect.left,i,NULL);

LineTo((HDC)wParam,rect.right - rect.left + 1,i);
}

//清除

SelectObject((HDC)wParam,hOldPenPozadina);

DeleteObject(hPenPozadina);

//绘制地图的元文件

HENHMETAFILE hemf = GetEnhMetaFile(L.\\\resources\\KartaDlg.emf);
ENHMETAHEADER emh;
GetEnhMetaFileHeader(hemf,sizeof(emh),&em; emh);

//从计算中删除状态栏

RECT r;

r.top = rect.top;
r.bottom = rect.bottom - 30;
r.left = rect.left;
r.right = rect.right;

//计算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;

//绘制图片。

PlayEnhMetaFile((HDC)wParam,hemf,& r);

//释放元文件句柄。

DeleteEnhMetaFile(hemf);

//此函数绘制绿色渐变和图标

drawFooter(HDC)wParam,rect,
RGB(0x48,0xAC,0xC6),RGB ,0x83,0x99));

// =========在状态栏中绘制正确的文本============= //

SetBkMode (HDC)wParam,TRANSPARENT);

SIZE sBaner; //正确定位所需的

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,LArial Black);

hfOld =(HFONT)SelectObject((HDC)wParam,hf); //需要正确的清除

GetTextExtentPoint32((HDC)wParam中,
LЦЕНТАРЗАОБНОВЉИВЕВОДНЕЕНЕРГЕТСКЕРЕСУРСЕ,
wcslen(LЦЕНТАРЗАОБНОВЉИВЕВОДНЕЕНЕРГЕТСКЕРЕСУРСЕ ),
& sBaner);

//正确放置

r.bottom = rect.bottom;
r.right = rect.left + sBaner.cx + 30;
r.left = rect.left + 30;
r.top = rect.bottom - rect.top - 30;

//绘制

DrawTextEx((HDC)wParam中,
LРУДАРСКОГЕОЛОШКИФАКУЛТЕТ\\\
ЦЕНТАРЗАОБНОВЉИВЕВОДНЕЕНЕРГЕТСКЕРЕСУРСЕ,
wcslen(LРУДАРСКОГЕОЛОШКИФАКУЛТЕТ\\\
ЦЕНТАРЗАОБНОВЉИВЕВОДНЕЕНЕРГЕТСКЕРЕСУРСЕ)
和R,DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_WORDBREAK,0);

SelectObject((HDC)wParam,hfOld); //正确清理

DeleteObject(hf);

// ==============状态栏中的正确文本================== //

lfHeight = -MulDiv(10,GetDeviceCaps((HDC)wParam,LOGPIXELSY),72);

hf = CreateFont(lfHeight,0,0,0,FW_BOLD,TRUE,
0,0,0,0,0,0,0,LArial);

hfOld =(HFONT)SelectObject((HDC)wParam,hf); //需要进行适当的清理

GetTextExtentPoint32((HDC)wParam中,
LДејанМиленић&放大器;АнаВрањеш©2013сваправазадржана,
wcslen(LДејанМиленић &АнаВрањеш©2013сваправазадржана),
& sBaner);

//正确放置

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;

//绘制

DrawTextEx((HDC)wParam中,
LДејанМиленић&放大器;АнаВрањеш©2013сваправазадржана,
wcslen(LДејанМиленић&放大器;АнаВрањеш©2013сваправазадржана),
和R,DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_WORDBREAK | DT_NOPREFIX,0);

//执行适当的清除

SelectObject((HDC)wParam,hfOld);

DeleteObject(hf);
}
return(INT_PTR)GetStockObject(NULL_BRUSH);

为了更完整,我提交 drawFooter 函数及其帮助函数:

  //用渐变刷填充三角形

void GradientTriangle (HDC MemDC,
LONG X1,LONG Y1,龙X2,LONG Y2,龙X3,LONG Y3,
COLORREF顶部,COLORREF底部)
{
TRIVERTEX顶点[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;

//创建一个GRADIENT_TRIANGLE结构,
//引用TRIVERTEX顶点。

GRADIENT_TRIANGLE gTriangle;

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

//绘制一个阴影三角形。

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

//绘制窗口的页脚(状态栏)

void drawFooter(HDC MemDC,RECT r,COLORREF top,COLORREF bottom)
{
//底部三角形

GradientTriangle(MemDC,
r.right,r.bottom,
(r.right - r.left)/ 2 ,
r.bottom - r.top - 15,
r.left,
r.bottom,
top,bottom);

//上三角形

GradientTriangle(MemDC,
r.right,r.bottom - r.top - 30,
- r.left)/ 2,
r.bottom - r.top - 15,
r.left,
r.bottom - r.top - 30,
top,底部);

// 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);

//直角三角形

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) ;

//绘制图标

DrawIconEx(MemDC,r.left,r.bottom - r.top - 30,
hiAdmin,//一个全局变量icon
30,30,NULL,NULL,DI_NORMAL);
}

启用视觉样式我不知道。



我没有处理 WM_ERASEBKGND WM_SIZE WM_MOVE 对话框无法调整大小。)。我已经尝试,但它没有帮助(返回 TRUE WM_ERASEBKGND InvalidateRect WM_SIZE WM_MOVE )。我在互联网上找不到任何帮助我。



问题:如何更改我的代码来修复我面对的错误? >

解决方案

您正在滥用 WM_CTLCOLORDLG 消息。



你应该返回 NULL_BRUSH

/ code>,或者甚至完全忽略该消息,并在 WM_ERASEBKGND 中进行背景绘制。



或者甚至更好,你可以忽略 WM_ERASEBKGND ,并在 WM_PAINT 中绘画,就像任何其他窗口。 / p>

UPDATE :下面几个注释问题似乎是调用顶点的顺序 GradientFill )三角形。这是:




  • 顶点按顺时针方向列出:绘制三角形。

  • 顶点


  • 或者也许是另一回事,我从来不能告诉... / p>

    无论如何,仍然有一个谜,为什么有时它的工作,无论顺序,为什么有时它只适用于一个特定的顺序。此外,这是记录在任何地方?



    我猜这可能是一个驱动程序/ 2D加速问题,所以它将取决于DC是在显示器上或在存储器上,但是很难说。


    I have a dialog box that should have a custom image as a background.

    I do not have the whole image as a bitmap or any other format, so I have to draw it from scratch.

    I use an icon (the male in the left bottom of the screenshot) , one EMF file (the map on the screen shot below), and the rest consists of a green gradient brush, light gray hatched brush, and text - all being drawn using GDI. The result of my drawing looks like this (the screen shot includes the controls too):

    The problem I face manifests when I move the dialog box to the left and then move it back to its original position. The artifacts happening are illustrated at the bottom of the picture in the next screenshot:

    The dialog box is the modeless one, and I draw the entire image in WM_CTLCOLORDIALOG returning NULL_BRUSH afterwards.

    Here is the relevant code snippet for the WM_CTLCOLORDIALOG handler ( note that I draw directly on the DC, there is no double buffering. The reason for it is that this was a quick test code things went wrong quickly):

    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);
    

    To make this even more complete, I submit the drawFooter function and its helper functions:

    // 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 );
    }
    

    Visual Styles are enabled - this might matter, I do not know.

    I did not handle WM_ERASEBKGND nor WM_SIZE or WM_MOVE ( dialog box can not be resized. ). I have tried but it did not help ( returning TRUE for WM_ERASEBKGND, and InvalidateRect for WM_SIZE and WM_MOVE ). I have found nothing on the internet to help me.

    Question: How to change my code to fix the error I face?

    解决方案

    You are abusing the WM_CTLCOLORDLG message. It is intended to provide an easy way to change the background color of the dialog, not to custom paint it.

    You should just return NULL_BRUSH there, or even ignore the message altogether, and do your background painting in WM_ERASEBKGND.

    Or maybe even better, you can ignore WM_ERASEBKGND and do your painting in WM_PAINT, just as any other window.

    UPDATE: After a few comments below the problem seems to be the order of the vertices in the call to GradientFill() triangles. That is:

    • The vertices are listed clockwise: the triangle is drawn.
    • The vertices are listed counter-clockwise: the triangle is not drawn.

    Or maybe is the other way around, I never can tell...

    Anyway, there is still the mystery of why sometimes it works no matter the order and why sometimes it only works with a specific order. And moreover, is this documented anywhere?

    I'm guessing that it may be a driver/2D-acceleration issue... so it will depend on whether the DC is on display or on memory, but it is difficult to say.

    这篇关于对话框不正确地重绘其背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆