Re[7]: Windows API Tab Control flickering
От: Sergey Россия  
Дата: 05.07.04 09:14
Оценка:
Hello, x84!
You wrote on Mon, 05 Jul 2004 09:07:41 GMT:

S>> Ты его маленький делай — одни закладки. Остальное в нем не нужно.


x> А причем тут его размер?


Мигать нечему будет. Т.е. окна, которые визуально должны быть расположены на
табконтроле, на самом деле лежат под ним и с ним не пересекаются. А
выглядить все это при желании может ровно так же, как с полноразмерным
табконтролом.

With best regards, Sergey.
Posted via RSDN NNTP Server 1.9 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[8]: Windows API Tab Control flickering
От: x84 Россия  
Дата: 05.07.04 09:32
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Мигать нечему будет. Т.е. окна, которые визуально должны быть расположены на

S>табконтроле, на самом деле лежат под ним и с ним не пересекаются. А
S>выглядить все это при желании может ровно так же, как с полноразмерным
S>табконтролом.

Блин... да вопрос-то был не как сделать мигание незаметным, а как от него избавиться вовсе.
Re[9]: Windows API Tab Control flickering
От: Sergey Россия  
Дата: 05.07.04 09:33
Оценка:
Hello, x84!
You wrote on Mon, 05 Jul 2004 09:32:13 GMT:

x> Блин... да вопрос-то был не как сделать мигание незаметным, а как от

x> него избавиться вовсе.

Тебе шашечки или ехать?

With best regards, Sergey.
Posted via RSDN NNTP Server 1.9 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[10]: Windows API Tab Control flickering
От: x84 Россия  
Дата: 05.07.04 09:58
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Тебе шашечки или ехать?


В данном случае, шашечки... с ними я уж и сам дальше поеду...
Re[6]: Windows API Tab Control flickering
От: Andrew S Россия http://alchemy-lab.com
Дата: 05.07.04 12:06
Оценка:
S>Ты его маленький делай — одни закладки. Остальное в нем не нужно.

Нет, его можно (нужно) делать как раз любым, по нужному размеру. Иначе некрасиво будет. А вот почему перестает мигать, когда вкладки делаешь дочерними не таб контролу, а окну — вероятно, стили CS_H(V)REDRAW заставляют его интенсивно перерисовываться _вместе_ с вкладками (т.е. инвалидируется весь регион контрола вместе с дочками) при сайзинге. Так же (диалоги вкладок выше его по Z ордеру) ничего подобного не происходит, поскольку присутствует явный клиппинг.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: Windows API Tab Control flickering
От: Dervish Россия http://www.dervish.ru
Дата: 12.07.04 11:22
Оценка: 26 (3)
Здравствуйте, x84, Вы писали:

x84>Вопрос, собственно, следующий: кто-нть может показать код, как на Windows API сделать таб контрол, который бы не мигал при ресайзе окна. Причем задача такова, чтобы таб контрол был "приклеен" внутри к правой границе родительского окна и сдвигался-раздвигался и уменьшал-увеличивал свой размер при ресайзе родительского окна.


Как уже говорилось, не суть важно какие механизмы используются для изменения размера TabControl-а, главное, что мерцание возникает всегда при изменении его размера.

Столкнулся с аналогичной задачей, мне тоже не понравилось, что TabControl мерцает и попробовал это дело исправить. Вроде как удалось успешно решить эту задачу, поэтому решил выложить код, может быть ещё кому-нибудь пригодится.

Если рассматривать именно TabControl, то мерцание в нём происходит по традиционным причинам: этот контрол честно отрабатывает сообщения WM_ERASEBKGND и WM_PAINT. Двойная буферизация в реализации этого контрола не предусмотрена.

Кстати, в отличии от других стандартных контролов Windows, TabControl не использует внутреннюю прорисовку, напрямую вызывая код рисования в обработке каких-то событий, а "по честному" делает InvalidateRect. Что, в данном случае, нам играет на руку.

Ситуация с мерцанием TabControl осложняется тем, что для этого класса окна прописаны стили CS_VREDRAW и CS_HREDRAW. Причины, по которым они были добавлены в общем понятны, но именно эти стили вместе с традиционной прорисовкой контрола и приводят к мерцанию.

Мой вариант решения проблемы мерцания основан на подмене оконной процедуры для TabControl-а (subclassing). Новая оконная процедура передаёт все приходящие сообщения "родной" процедуре TabControl-a, но подменяет обработку двух сообщений: WM_ERASEBKGND и WM_PAINT.

WM_ERASEBKGND обрабатывается тривиально: никаких действий не производится, просто возвращается ненулевой код возврата, говорящий, что основа окна подготовлена.

А вот WM_PAINT обрабатывается посложнее: чтобы самому не рисовать TabControl (если рисовать самому, то запросто может получиться новый контрол, да и пятью строчками кода там не обойдёшься — слишком много вариантов в реализациях этого контрола, слишком много стилей влияет на его вид), для прорисовки вызывается обработчик стандартного сообщения WM_PRINTCLIENT, который рисует контрол в битмапе. А после этого сформированный битмап просто копируется на экран. Таким образом получается, что для фактической прорисовки окна TabControl-a используется всего один BitBlt, в итоге — никакого мерцания.

А теперь код новой оконной процедуры:


WNDPROC pTabControlProc;

LRESULT CALLBACK TabCtrlSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    if (uMsg == WM_ERASEBKGND)
        return 1;
    if (uMsg == WM_PAINT) {
        // Чтобы поменьше генерилось WM_ERASEBKGND, сэкономим время на
        // диспетчеризации сообщений.
        ValidateRect (hWnd, NULL);

        HDC hControlDC;
        HDC hMemoryDC;
        RECT rc;        // Для определения размеров окна
        HBITMAP hBitmap;    // Битмап для двойной буферизации
        HGDIOBJ hSave;        // Оригинальный битмап из hMemoryDC

        GetClientRect (hWnd, & rc); // TabControl не использует non-client area

        hControlDC = GetDC (hWnd);
        hMemoryDC = CreateCompatibleDC (hControlDC);

        hBitmap = CreateCompatibleBitmap (hControlDC, rc.right, rc.bottom);
        hSave = SelectObject (hMemoryDC, hBitmap);

        // Очистим буфер-битмап, зальём его фоном
        CallWindowProc (pTabControlProc, hWnd, WM_ERASEBKGND, (WPARAM)hMemoryDC, 0);

        // Прорисуем контрол в битмапе
        CallWindowProc (pTabControlProc, hWnd, WM_PRINTCLIENT, (WPARAM)hMemoryDC, PRF_CLIENT);

        // Ну и нарисуем контрол на дисплее
        BitBlt (hControlDC, 0, 0, rc.right, rc.bottom, hMemoryDC, 0, 0, SRCCOPY);

        DeleteObject (SelectObject (hMemoryDC, hSave));
        DeleteDC (hMemoryDC);
        ReleaseDC (hWnd, hControlDC);

        return 0;
    }
    return CallWindowProc (pTabControlProc, hWnd, uMsg, wParam, lParam);
}


А вот так создаётся немерцающий TabControl:

    hControl = CreateWindowEx (dwExStyle, WC_TABCONTROL, pCaption,
        dwControlStyle, 0, 0, 50, 50, hParent,
        (HMENU)iControlId, hInstance, NULL);

    if (::IsWindow (hControl)) {
        pTabControlProc = (WNDPROC) SetWindowLong (
            hControl, GWL_WNDPROC, (LONG) TabCtrlSubclassProc
        );
    }


Надеюсь, что это поможет.
Re[2]: Windows API Tab Control flickering
От: WoldemaR Россия  
Дата: 12.07.04 14:34
Оценка:
Здравствуйте, Dervish, Вы писали:

D>Если рассматривать именно TabControl, то мерцание в нём происходит по традиционным причинам: этот контрол честно отрабатывает сообщения WM_ERASEBKGND и WM_PAINT. Двойная буферизация в реализации этого контрола не предусмотрена.


Достаточно обеспечить атомарность обработки WM_ERASEBKGND и WM_PAINT, без двойной буферизации.

LRESULT CALLBACK CWrapperTab::TabCtrlSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_ERASEBKGND)
        return 0;
    if (uMsg == WM_PAINT)
    {
        ::ValidateRect(hWnd, NULL);

        HDC hControlDC = ::GetDC(hWnd);

        CallWindowProc(pTabControlProc, hWnd, WM_ERASEBKGND, (WPARAM)hControlDC, 0);
        CallWindowProc(pTabControlProc, hWnd, WM_PRINTCLIENT, (WPARAM)hControlDC, PRF_CLIENT);

        ::ReleaseDC(hWnd, hControlDC);

        return 0;
    }
    return CallWindowProc(m_pTabProc, hWnd, uMsg, wParam, lParam);
}
Re[3]: Windows API Tab Control flickering
От: Аноним  
Дата: 18.03.05 10:21
Оценка:
Подскажите, пожалуйста, как прикрутить вышеприведённый код к ListView, а то Header не прорисовывается пока мышку на него не наведёшь. Спасибо.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.