Доброго времени суток всем.
У меня есть класс CListCtrlEx, который я переопределил от обычного CListCtrl. Этот список имеет стиль LVS_REPORT, LVS_OWNERDRAWFIXED и LVS_EX_GRIDLINES. Я прикрутил возможность смены шрифта для этого списка. Она вроде и работает, но есть одно но — если я меняю шрифт и перед этим не делаю скроллинг списка, то тогда все элементы списка перерисовываются правильно, но если я сначала сделаю скроллинг, а затем сменю шрифт, то получится, что элементы списка "съедут" чуть ниже своего положения в сетке списка, т. е. это будет выглядеть как текст перечёркнутый линиями сетки.
Код замены шрифта:
LRESULT CListCtrlEx::OnSetFont(WPARAM wParam, LPARAM)
{
LRESULT res = Default();
Здравствуйте, brightside90, Вы писали:
B>Доброго времени суток всем. B>У меня есть класс CListCtrlEx, который я переопределил от обычного CListCtrl. Этот список имеет стиль LVS_REPORT, LVS_OWNERDRAWFIXED и LVS_EX_GRIDLINES. Я прикрутил возможность смены шрифта для этого списка. Она вроде и работает, но есть одно но — если я меняю шрифт и перед этим не делаю скроллинг списка, то тогда все элементы списка перерисовываются правильно, но если я сначала сделаю скроллинг, а затем сменю шрифт, то получится, что элементы списка "съедут" чуть ниже своего положения в сетке списка, т. е. это будет выглядеть как текст перечёркнутый линиями сетки.
B>Код замены шрифта:
<skipped>
1.Почему просто вместо этого не послать ему WM_SETFONT ?
По коду
2. В MeasureItem не нужно ничего рисовать для измерения размера высоты шрифта. На это GetTextExtentPoint32 есть.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, brightside90, Вы писали:
B>>Доброго времени суток всем. B>>У меня есть класс CListCtrlEx, который я переопределил от обычного CListCtrl. Этот список имеет стиль LVS_REPORT, LVS_OWNERDRAWFIXED и LVS_EX_GRIDLINES. Я прикрутил возможность смены шрифта для этого списка. Она вроде и работает, но есть одно но — если я меняю шрифт и перед этим не делаю скроллинг списка, то тогда все элементы списка перерисовываются правильно, но если я сначала сделаю скроллинг, а затем сменю шрифт, то получится, что элементы списка "съедут" чуть ниже своего положения в сетке списка, т. е. это будет выглядеть как текст перечёркнутый линиями сетки.
B>>Код замены шрифта:
PD><skipped>
PD>1.Почему просто вместо этого не послать ему WM_SETFONT ?
PD>По коду PD>2. В MeasureItem не нужно ничего рисовать для измерения размера высоты шрифта. На это GetTextExtentPoint32 есть.
1. По-идее, я сначала делаю вызов SetFont(...), после которого происходит обработка сообщения WM_SETFONT, а как сделать это без такого вызова?
2. Я делаю всё почти как здесь http://www.codeproject.com/Articles/1401/Changing-Row-Height-in-an-owner-drawn-Control с тем лишь отличием, что вместо GetTextMetrics(hDC, &tm); решил нарисовать квадратик, чтобы вычислить высоту шрифта. Да, можно сделать это и через GetTextExtentPoint32(), но и там, судя по описанию придётся "написать" строку текста длиной хотя бы в один символ, что не критично.
Если в теле OnSetFont(...) не посылать никаких сообщений, чтобы вызвать MeasureItem, то шрифт в списке изменится, а высота строк останется прежней
WM_WINDOWPOSCHANGED вообще-то не посылают сами. Это нотификация о том, что положение окна изменилось вследствие каких-то причин. Оно придет, конечно, но изменения-то нет.
Sent to a window whose size, position, or place in the Z order has changed as a result of a call to the SetWindowPos function or another window-management function.
Попробуй заменить на SetWindowPos, а скорее просто на Invalidate.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, brightside90, Вы писали:
PD>Похоже, вот в чем дело
PD>WINDOWPOS wp; PD>wp.hwnd = m_hWnd; PD>wp.cx = rc.Width(); PD>wp.cy = rc.Height(); PD>wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER; PD>SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
PD>WM_WINDOWPOSCHANGED вообще-то не посылают сами. Это нотификация о том, что положение окна изменилось вследствие каких-то причин. Оно придет, конечно, но изменения-то нет.
PD>Sent to a window whose size, position, or place in the Z order has changed as a result of a call to the SetWindowPos function or another window-management function.
PD>Попробуй заменить на SetWindowPos, а скорее просто на Invalidate.
Если я вызову просто Invalidate, то MeasureItem(...) не откликнется, да и в случае с SetWindowPos, оно тоже спит.
Делаю так:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, brightside90, Вы писали:
B>>Может быть с флагами надо что-то намудрить, но я уже запутался)
PD>Посмотри вот здесь
PD>http://sources.ru/cpp/mfc/t9107.htm
PD>Anyway, I added a handler PD>for WM_MEASUREITEM in my dialog class and called CMyListCtrl::MeasureItem() PD>myself and everything works.
PD>Попробуй, может быть это и есть самое простое. А потом Invalidate.
Хе, осталось понять только как он инициализировал LPMEASUREITEMSTRUCT, чтобы вызвать MeasureItem(), а способ с двумя подряд вызовами SetWindowPos() не прокатывает.
PD>>Попробуй заменить на SetWindowPos, а скорее просто на Invalidate.
B>Если я вызову просто Invalidate, то MeasureItem(...) не откликнется, да и в случае с SetWindowPos, оно тоже спит. B>Делаю так: B>
Здравствуйте, Carc, Вы писали:
PD>>>Попробуй заменить на SetWindowPos, а скорее просто на Invalidate.
B>>Если я вызову просто Invalidate, то MeasureItem(...) не откликнется, да и в случае с SetWindowPos, оно тоже спит. B>>Делаю так: B>>
Это тоже не срабатывает, причём, если оставить в таком виде параметры SetWindowPos, то MeasureItem не вызовется, а вот если добавить к ширине или высоте прямоугольника хотя бы 1, то MeasureItem тут же просыпается Но, тем не менее, это не помогает.
Пока сделал так:
раз уж если вертикальный скролл стоит в своём начальном положении и при этом шрифт хорошо изменяется, то если мы поменяли его положение, нужно сначала его откатить после создания шрифта, но до его установки:
int nTopIndex = GetTopIndex();
if (nTopIndex != 0)
{
SetRedraw(FALSE);
RECT rect;
if (GetItemRect(nTopIndex, &rect, LVIR_LABEL))
{
CSize size;
size.cx = 0;
size.cy = -(nTopIndex * rect.bottom - rect.top);
Scroll(size);
}
}
А после возврата из MeasureItem вызвать
EnsureVisible(m_nItem, FALSE);
SetRedraw(TRUE);
чтобы откатить положение скролла к последнему выделенному элементу списка (хотя бы к нему, даже если его положение было не обязательно последним положением соответствовавшим положению скролла до смены шрифта).
Есть опасение, что, если в списке будет содержаться большое количество записей, то такие фокусы будут дорого стоить.
Здравствуйте, brightside90, Вы писали:
B>Есть опасение, что, если в списке будет содержаться большое количество записей, то такие фокусы будут дорого стоить.