调整窗口大小时,公共控件未正确绘制

Posted

技术标签:

【中文标题】调整窗口大小时,公共控件未正确绘制【英文标题】:Common controls are not properly painted when I resize window 【发布时间】:2015-01-21 00:28:06 【问题描述】:

简介:

我正在创建带有子对话框作为页面的选项卡控件。

我通过#pragma 评论启用了Visual Styles。我还打电话给InitCommonControlsEx#pragma comment( lib, "comctl32.lib" )

最初,当窗口加载时,对话框及其常用控件具有适当的背景,请参见下图:

在调整大小时,事情不是那么一致 -> 背景开始明显不匹配。我将在下面提供截图:

您可以清楚地看到checkboxstatic control 具有不正确的背景,而在我看来dialog box(作为子控件创建)具有适当的背景。

于 2014 年 11 月 24 日编辑:

将控件封装到group boxes 后似乎没有绘画问题。我的显示器是旧的 CRT(Samsung SyncMaster 753s),我的视力不好,但似乎一切正常。窗口在调整大小时仍然闪烁可怕,但I have tried everything in my power 修复它。

问题:

我该如何解决这个问题?

我为解决这个问题所做的努力:

我还没有找到任何东西,但我在输入这个问题时仍然在盯着看......

相关信息:

以下是用于说明问题的演示创建说明:

1.) 在Visual Studio 中创建空的C++ 项目;

2.) 添加头文件,将其命名为pomocne_funkcije.h 并复制/粘贴以下内容:

#include <windows.h>
#include <windowsx.h>
#include <comutil.h>
#include <commctrl.h>
#include <stdio.h>
#include <vector>
#include <ole2.h>
#include <string>
#include <stdlib.h>
#include <locale.h>
#include <Uxtheme.h>

#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")

#pragma comment( lib, "comctl32.lib")
#pragma comment( lib,"Msimg32.lib")
#pragma comment( lib, "comsuppw.lib")
#pragma comment( lib, "UxTheme.lib")

3.) 在资源编辑器中创建对话框,添加复选框静态控件。

为对话框设置以下内容:

边框:无 控制:真 控制父级:true 风格:儿童 系统菜单:错误

4.) 这是main.cpp 的代码:

#include "pomocne_funkcije.h"

static HINSTANCE hInst;

// dialog procedure for firts tab
INT_PTR CALLBACK Ugovori(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    
    case WM_INITDIALOG:
        
            EnableThemeDialogTexture( hDlg, ETDT_ENABLETAB );
        
        return (INT_PTR)TRUE;
    
    return (INT_PTR)FALSE;


// main window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

    static HWND hDlgFirstTab;  // handle to the first page dialog box
    switch(msg)
    
    case WM_CREATE:
        
            RECT rcClient = 0;
            ::GetClientRect( hwnd, &rcClient );

            HWND hwndTab = CreateWindowEx( 0, WC_TABCONTROL, 
                L"Ugovori", WS_CHILD | WS_VISIBLE, 
                10, 10, rcClient.right - rcClient.left - 20,
                rcClient.bottom - rcClient.top - 63, 
                hwnd, (HMENU)3000, 
                ((LPCREATESTRUCT)lParam)->hInstance, 0 );

            TCITEM tci = 0;

            tci.mask = TCIF_TEXT;
            tci.pszText = L"Основни подаци";
            TabCtrl_InsertItem( hwndTab, 0, &tci );

            // set font so cyrilic symbols can be properly displayed instead of ???
            SendMessage( hwnd, WM_SETFONT, 
                (WPARAM)(HFONT)GetStockObject(DEFAULT_GUI_FONT),
                (LPARAM)TRUE );

            SendMessage( hwndTab, WM_SETFONT, 
                (WPARAM)(HFONT)GetStockObject(DEFAULT_GUI_FONT),
                (LPARAM)TRUE );

            // create page ( dialog box )
            hDlgFirstTab = CreateDialog( ((LPCREATESTRUCT)lParam)->hInstance,
                MAKEINTRESOURCE(IDD_DIALOG1), 
                hwnd, 
                (DLGPROC)Ugovori );  // dialog procedure 

            ShowWindow( hDlgFirstTab, SW_SHOW );

        
        return 0L;
    case WM_MOVE:
    case WM_MOVING:
    case WM_SIZING:
    case WM_SIZE:
        
            RECT rcClient = 0;
            GetClientRect( hwnd, &rcClient );

            SetWindowPos( GetDlgItem( hwnd, 3000 ), NULL, 
                rcClient.left + 10, // move it away from window edge by 10 pixels
                rcClient.top + 10,  // move it away from window edge by 10 pixels
                rcClient.right - rcClient.left - 20,  
                // - 63 was the size of the button, 
                // but I have deleted that button here to preserve space
                rcClient.bottom - rcClient.top - 63, 
                SWP_NOZORDER | SWP_NOCOPYBITS );

            // get tab control's client rectangle
            GetClientRect( GetDlgItem( hwnd, 3000 ), &rcTab );

            //============= place dialog box into tab's client area
            MapWindowPoints( GetDlgItem( hwnd, 3000 ), hwnd, 
                (LPPOINT)(&rcTab), 2 );
            // get tab's display area
            TabCtrl_AdjustRect( GetDlgItem( hwnd, 3000 ), 
                FALSE, &rcTab );
            // move dialog box
            SetWindowPos(hDlgFirstTab, NULL, 
                rcTab.left, rcTab.top,
                rcTab.right - rcTab.left, 
                rcTab.bottom - rcTab.top, 
                SWP_NOZORDER);

            //========================= done
            // repaint window
            InvalidateRect( hwnd, NULL, FALSE );
        
        return 0L;
    case WM_ERASEBKGND:
        return 1L;
    case WM_PAINT:
        
            PAINTSTRUCT ps = 0;
            HDC hdc = BeginPaint( hwnd, &ps );
            SendMessage( hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0 );
            EndPaint( hwnd, &ps );
        
        return 0L;
    case WM_PRINTCLIENT:
        
            RECT rcClient = 0;
            GetClientRect( hwnd, &rcClient );

            FillRect( (HDC)wParam, &rcClient, 
                (HBRUSH)GetStockObject(WHITE_BRUSH) );
        
        return 0L;
    case WM_CLOSE:
        ::DestroyWindow(hwnd);
        return 0L;
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0L;
    default:
        return ::DefWindowProc( hwnd, msg, wParam, lParam );
    
    return 0;


// WinMain

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, 
                   int nCmdShow)

    // store hInstance in global variable for later use

    hInst = hInstance;

    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    // initialize common controls

    INITCOMMONCONTROLSEX iccex;
    iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_UPDOWN_CLASS | 
       ICC_STANDARD_CLASSES | ICC_TAB_CLASSES;
    InitCommonControlsEx(&iccex);

    // register main window class

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION );
    wc.hCursor = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"Main_Window";
    wc.hIconSm = LoadIcon( hInstance, IDI_APPLICATION );

    if(!RegisterClassEx(&wc))
    
        MessageBox(NULL, 
            L"Window Registration Failed!", L"Error!", 
            MB_ICONEXCLAMATION | MB_OK);

        return 0;
    

    // create main window

    hwnd = CreateWindowEx( 0, L"Main_Window", 
        L"Contract manager", 
        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        NULL, NULL, hInstance, 0 );

    if(hwnd == NULL)
    
        MessageBox(NULL, L"Nemogu da napravim prozor!", L"Greska!",
            MB_ICONEXCLAMATION | MB_OK);

        return 0; 
    

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    

    return Msg.wParam;

我在Windows XP 上使用C++WinAPIVisual Studio 2008 工作。

【问题讨论】:

我会调用EnableThemeDialogTexture 是问题的一部分。您是否尝试过忽略它? I mostly solved the transparent control issue here. 不知道闪烁(我也不完全确定我所做的会如何影响闪烁量,因为我的用例有一个垃圾收集器);需要更多地阅读这个问题...... @andlabs:是的,我知道,我给你留下了评论:) 实现WM_PRINTCLIENT 并在WM_CTLCOLORSTATIC 中使用DrawThemeParentBackground 解决了单选按钮、复选框和静态控制的问题。但是,例如,如果您添加轨迹栏,您将被搞砸:(我能说什么,MS Visual Styles...如此不必要的痛苦... 是的,弄清楚这些会很有趣... =P 但是,是的,闪烁是我仍然需要弄清楚的事情,而且我提到的停止世界垃圾收集器没有帮助 = P @Cheersandhth.-Alf:从WM_INITDIALOG 中删除EnableThemeDialogTexture 会使子对话框没有选项卡控件的背景颜色。由于您的评论得到了赞成,我想进一步调查。正如你所说,我已经删除了EnableThemeDialogTexture,并在主窗口的WM_CREATE 处理程序中调用了它。效果是一样的 - > 对话框有正确的背景,但调整大小后仍然可以看到不匹配...我会更加努力并发布我的结果。感谢您尝试提供帮助。最好的问候。 【参考方案1】:

您的选项卡对话框按 Z 顺序位于选项卡控件下方。这会在第一次调整大小时导致疯狂的过度绘制问题。将标签对话框作为子窗口添加到主窗口后,调用 SetWindowPos(tab, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE) 将它们移动到 Z 顺序的顶部。

有这个确切的问题;我花了好几天才弄明白。我在 Visual Studio 中创建了一个简单的应用程序:

    对 ComCtrl v 6 的清单引用 InitCommonControlsEx() 带有选项卡控件的对话框 选项卡内容的子对话框(与选项卡同级) 在子对话框中,一个单选按钮和一个静态 不要对WM_PRINTCLIENT 或类似的东西进行花哨的处理 只需在子对话框的WM_INITDIALOGEnableThemeDialogTexture()

我在 XP 上检查了一下……它运行良好,看起来很漂亮,除了闪烁。

我添加了WS_CLIPCHILDREN 并突然能够完美地重现您的屏幕截图。我一开始以为是这个原因。

我一直推并添加WS_COMPOSITED以防止闪烁,标签窗口突然消失了——完全被标签的背景覆盖了。现在我意识到 Z 顺序有问题。

子窗口总是在 Z 顺序的底部创建,即在您的选项卡控件下方。您的代码永远不会将它们向上移动。选项卡仅由纯粹的运气/透支显示,产生您观察到的工件。修复 Z 顺序,就不会再有工件了。

【讨论】:

自从我遇到这个问题已经 4 年了,我再也无法访问 XP 机器了。尽管我无法再测试您的解决方案,但我已赞成您的回答。如果我设法测试它并且它有效,我将正式接受它。感谢你的付出! :) 好的!我最初将错误归咎于WS_CLIPCHILDREN,但更多测试表明这是窗口的Z 顺序,使用WS_CLIPCHILDREN 只是问题出现的一种方式(WS_EX_COMPOSITED 是另一种方式)。我相应地更新了帖子。 现在你提到它的时候,我也遇到过这个问题。直到今天我都记得很清楚,因为它太奇怪了……我需要抽出时间来测试一下你的建议,因为我很长时间不做WinAPI,而且工作很忙。非常感谢你的努力,我忘了告诉你(现在)我已经赞成你的回答。一旦我有时间自己测试一下(如果您的解决方案有效),我将正式接受您的答案并奖励赏金(我认为您应得的)。问候。 不着急。我知道这是一个老问题,我主要是为其他可能有同样问题并在搜索网络后登陆这里的人回答的(可能包括我未来的自己):) 最好的问候!

以上是关于调整窗口大小时,公共控件未正确绘制的主要内容,如果未能解决你的问题,请参考以下文章

调整窗口大小时是不是可以完全消除闪烁?

MFC 调整大小对话框和子窗口绘制问题

使用 OpenGL 和 SDL 处理窗口大小调整

C#,实现窗口大小改变时窗口内的控件自动调整位置和大小时,groupbox内的控件为啥不自动调整

C#,实现窗口大小改变时窗口内的控件自动调整位置和大小时,groupbox内的控件为啥不自动调整??求解

如何在调整窗口大小时暂停 GtkDrawingArea 绘制回调?