【问题标题】:My application slightly flickers on resize despite applying known techniques for anti-flickering尽管应用了已知的防闪烁技术,但我的应用程序在调整大小时会略微闪烁
【发布时间】:2015-01-20 21:34:42
【问题描述】:

我有来自WM_ERASEBKGND 处理程序的returned 1L,通过添加InvalidateRect( hWnd, NULL, FALSE ); 处理了WM_SIZE,并从我的窗口类中删除了CS_HREDRAW | CS_VREDRAW 样式。

闪烁在选项卡控件上最为明显。这是一个说明问题的小演示:

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.) 创建名为main.cpp.cpp 文件并复制/粘贴以下内容:

#include "pomocne_funkcije.h"

static HINSTANCE hInst;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    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 );

            tci.pszText = L"Анекси";
            TabCtrl_InsertItem( hwndTab, 1, &tci );

            tci.pszText = L"Подиѕвођачки радови";
            TabCtrl_InsertItem( hwndTab, 2, &tci );

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

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

        }
        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, rcClient.top + 10, 
                rcClient.right - rcClient.left - 20, 
                rcClient.bottom - rcClient.top - 63,
                SWP_NOZORDER | SWP_NOCOPYBITS );

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

我正在使用C++WinAPIWindows XP 上工作Visual Studio 2008

问题:

如何消除选项卡控件(以及我的窗口的其余部分)的闪烁?

谢谢。最好的祝福。

【问题讨论】:

  • 为什么要调整WM_MOVE/WM_MOVING 上的选项卡控件的大小?它不会改变大小,这意味着父窗口已经移动。你也可以忽略WM_SIZING,只寻找WM_SIZE。如果我去掉三个不必要的 case 语句,在 Windows 8 上调整窗口大小时它根本不会闪烁。
  • 乔纳森是正确的——你正在处理你不应该处理的消息;您实际上是通过为每个中间尺寸更改进行多次重绘来强制闪烁。
  • @JonathanPotter:我已经删除了提到的消息,但是标签控件在调整大小时会严重闪烁。我在窗口底部添加了简单的按钮,它不会闪烁。我认为问题出在选项卡控制上,但是你又说在 Windows 8 上一切正常......我不知道该怎么办,所以我会谷歌搜索“win32 tab control flicker on xp”,希望能找到一个解决方案...
  • @JeffD.:我已经删除了提到的消息,但是标签控件在调整大小时会严重闪烁。我在窗口底部添加了简单的按钮,它不会闪烁。我觉得问题出在tab control上……不知道怎么办,所以我去google一下“win32 tab control flicker on xp”,希望能找到解决办法……
  • 一些控件只是闪烁,您无能为力 - 过去我自己在这方面花费了数周时间。我想出的最佳解决方案是在调整元素大小时使用SWP_NOREDRAW,使用WM_PRINTCLIENT 将整个父窗口的客户区绘制到内存位图中,然后将其blit 到屏幕上(有效地双缓冲) .但这有其自身的问题,因为并非所有控件都支持WM_PRINTCLIENT(或者即使支持也有问题),这意味着您仍然需要很多小工具才能使其正常工作。

标签: c++ winapi tabs flicker


【解决方案1】:

我认为你不需要这条线:

InvalidateRect( hwnd, NULL, FALSE );

由于在调整表单大小时已经强制重新绘制。 我删除了它,窗口仍然显示和重绘,没有闪烁。

【讨论】:

  • 试过了,tab控件还在闪烁... :(
  • 您需要为您的应用程序启用视觉样式吗?通过不包括 UxTheme.lib 或调用: SetWindowTheme(hwnd, L" ", L" ");根据msdn.microsoft.com/en-us/library/windows/desktop/…
  • 我已启用视觉样式。禁用视觉样式不是一种选择,但我理解你的观点-> 我会尝试看看当我关闭视觉样式并报告我的结果时会发生什么。虽然您的回答并没有解决我的问题,但我已将赏金奖励给您,以感谢您的努力。最好的问候。
  • 谢谢,希望您能找到适合您的解决方案。
猜你喜欢
  • 2019-12-06
  • 1970-01-01
  • 2019-01-05
  • 2013-04-26
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 2012-05-29
  • 2023-03-28
相关资源
最近更新 更多