Здравствуйте, 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
);
}
Надеюсь, что это поможет.