Переопределение класса CListCtrl и OnTimer

#c #windows #winapi #mfc #clistctrl

#c #Windows #winapi #mfc #clistctrl

Вопрос:

Я не уверен, делаю ли я что-то недокументированное. Я создал свой собственный класс, производный от CListCtrl, а затем переопределил в нем обработчик OnTimer:

 void CListCtrl2::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: Add your message handler code here and/or call default

    switch(nIDEvent)
    {
    case MY_TIMER_ID:
        {
            //Do my processing
            doMyProcessing();
        }
        break;

    default:
        {
            //Default
            CListCtrl::OnTimer(nIDEvent);
        }
        break;
    }
}
 

Но что мне кажется странным, так это то, что эта процедура OnTimer() вызывается с идентификаторами таймера, которые не являются моими. Например, только из быстрого исследования контрольных точек отладчика выясняется, что мой default обработчик вызывается с nIDEvent установленным значением 45 и 43 .

Есть ли какие-то зарезервированные идентификаторы таймера, которые я должен избегать использовать самостоятельно?

Ответ №1:

Из CListCtrl документации мы видим этот текст:

Также смотрите:

И из этой статьи некоторые соответствующие выдержки:

Если вы вызываете функцию SetTimer для отправки периодических сообщений WM_TIMER элементу управления list, вы можете обнаружить, что обработчик сообщений WM_TIMER (функция OnTimer) для элемента управления list вызывается только дважды.

….

Элемент управления списком использует таймер для редактирования меток и для прокрутки. При обработке сообщения таймера, если идентификатор таймера является вашим собственным таймером, не вызывайте обработчик по умолчанию (CListCtrl::OnTimer).

Итак, это подтверждает то, что вы наблюдаете. Элемент управления списком использует таймер. Я не могу найти документацию для конкретных используемых идентификаторов. Я предполагаю, что Microsoft не хотела бы фиксировать документирование конкретных идентификаторов, которые использовались. Они будут рассматривать реализацию элемента управления как закрытую и хотели бы сохранить возможность использования большего количества идентификаторов таймера в будущих версиях. Но, как указывает IInspectable, они могли бы сделать это, зарезервировав диапазон идентификаторов.

Я рекомендую рассматривать таймер элемента управления списком как выходящий за рамки и зарезервированный для использования элементом управления. Для вашего производного класса используйте другой таймер. Создайте окно только для сообщений и используйте его для получения событий таймера. Для достижения этой цели вы можете создать подкласс CWnd .

Комментарии:

1. Я не понимаю, как можно ожидать отсутствия документирования идентификаторов таймера. Зарезервированный диапазон является частью общедоступного интерфейса, поскольку он влияет на реализацию производного класса. Указание диапазона (аналогично WM_MOUSEFIRST / WM_MOUSELAST ) не означает, что реализация обязана использовать определенные идентификаторы для определенных таймеров. Он просто предлагает реализации возможность выбора из допустимого диапазона идентификаторов. И позволяет клиенту реализовать надежное решение.

2. @IInspectable Справедливое замечание. Я имел в виду, что я ожидал бы, что MS не будет использовать только определенные. Но, конечно, резервирование диапазона было бы разумным решением. Я бы, конечно, ожидал, что они, по крайней мере, задокументируют, что элемент управления использует таймер. Я попытался очистить этот текст.

3. После вашего редактирования я бы выразился еще сильнее: документирование диапазона используемых идентификаторов таймера является обязательным для обеспечения реализации надежной специализации. Учитывая поведение SetTimer API, вы должны предоставить уникальный идентификатор. Даже если система назначает вам идентификатор, ваш начальный nIDEvent идентификатор не должен сталкиваться с уже используемым идентификатором — иначе он заменяет этот таймер вместо создания нового. Таким образом, использование таймеров в a CListCtrl -implementation невозможно, если только не выбрать излишне утомительное решение, изложенное в вашем последнем абзаце.

4. @IInspectable Возможно, MS не ожидала, что кто-либо будет подклассировать этот элемент управления. Возможно, они просто ошиблись. Тем не менее, это то, что есть. Учитывая, что идентификаторы не задокументированы, я не вижу особой альтернативы утомительному решению моего последнего абзаца.

5. Возможно, я ошибался в отношении SetTimer API. Передача 0 в качестве nIDEvent параметра (т. Е. Недопустимого идентификатора) создаст таймер и вернет назначенный системой идентификатор, который можно сохранить и использовать для обновления и отключения этого таймера. Предполагая CListCtrl , что делает то же самое, коллизий нет. Это также может быть возможным решением. (Хотя мне трудно прочитать наблюдаемое поведение в отношении назначения идентификатора в документации для SetTimer .)