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 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
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 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, 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
);
}
Надеюсь, что это поможет.
Здравствуйте, 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);
}
Подскажите, пожалуйста, как прикрутить вышеприведённый код к ListView, а то Header не прорисовывается пока мышку на него не наведёшь. Спасибо.