В предыдущих лекциях мы много говорили о классах и, в частности, рассматривали возможность применения класса в качестве упаковки тех или иных стандартных средств. Такой прием позволяет инкапсулировать в классе стандартные средства, - функции API, элементы управления, - скрыть многие детали работы с ними, а, зачастую, и предоставить конечному пользователю дополнительный сервис. Этот полезный прием целесообразно применять всякий раз, когда предполагается работа с функциями Win32 API. Все эти вопросы объявления функций, трансляции из одной формы описания в другую, описание многих параметров, не используемых по существу задачи, следует скрыть в описании класса, организовав интерфейс класса, более разумный с позиций конечного пользователя.
Каждый из наших примеров работы с функциями Win32 API достоин лучшей упаковки и представления его в виде класса. Мы ограничимся одним последним примером и представим в виде класса работу с таймером. Пожалуй, этот пример наиболее интересен, поскольку он представляет особый случай из-за наличия Callback функции, которая, конечно же, не может быть стандартизована и должна быть задана конечным пользователем, в интересах которого и строится класс.
Поскольку мы уже хорошо знакомы с тем, как строятся классы и как работать с функциями Win32 API, то нам осталось рассказать, как объединить эти две вещи в единое целое. Никаких особых деталей здесь нет. Общая стратегия такова:
Применим эту общую схему для создания класса ВашТаймер. Начнем с проектирования его интерфейса. Естественно, целью класса является предоставление пользователю возможности создавать таймер, посылающий сообщения с заданным интервалом, и удалять его, когда необходимость в нем исчезнет. Пользователь не должен ничего знать о функциях Win32 API, об операторах Declare, преобразовании типов. Кажется естественным с этих позиций в интерфейс класса включить два метода: "СоздатьТаймер" и "УдалитьТаймер" и свойство "ИнтервалТаймера", доступное для чтения и записи. Методы не имеют параметров, что облегчает работу с ними. Чтобы созданный таймер посылал сообщения с заданным интервалом, необходимо предварительно установить подходящее значение свойства, но можно этого и не делать, - в этом случае будет использоваться значение по умолчанию.
Рассматриваемый нами случай упаковки функций Win32 API особый, поскольку одна из этих функций требует вызова Callback функции. Заметьте, функции обратного вызова не должны принадлежать упаковке, - нашему классу. Они не являются стандартными средствами, это функции, создаваемые пользователем. Поэтому они должны находиться вне модуля класса, - в стандартном классе, созданном пользователем, там, где он будет создавать и объекты класса ВашТаймер. Чтобы не возникала соблазна поместить в класс функцию обратного вызова, такая возможность исключается синтаксически. Обратите, однако, внимание, что созданный класс предъявляет определенные требования к заголовку функции обратного вызова и даже диктует ее имя. Но обо всем по порядку и давайте вначале рассмотрим описание класса ВашТаймер:
Некоторые комментарии к этому тексту:
СоздатьТаймер и УдалитьТаймер, а также процедуры - свойства Property Get и Property Let ИнтервалТаймера, позволяющие взаимодействовать с закрытым свойством Интервал.Declare, описывающие функции Win32 API SetTimer и KillTimer, уже упомянутое свойство Интервал и свойство IdEv, хранящее идентификатор таймера, о котором конечный пользователь может и не знать. Class_Initialize и Class_Terminate. В конструкторе инициализируется свойство Таймер, значение которого устанавливается по умолчанию, равным одной секунде. В деструкторе класса таймер уничтожается, если он не был удален до этого.TimerProc. Процедура с таким именем и уже упоминавшимися требованиями к ее заголовку должна быть описана в стандартном модуле класса, созданным конечным пользователем.Рассмотрим, как работать с классом ВашТаймер. Мы не стали изобретать ничего нового, - в тестовый документ добавили две кнопки Start1 и Finish1, которые работают также как и их тезки Start и Finish, но вызывают для этого методы и свойства объекта MyTimer класса ВашТаймер. В модуле, где объявлен соответствующий объект, находится и процедура обратного вызова TimerProc. Вот соответствующий текст этого модуля:
Комментируя этот текст, следует заметить, что введение обертывающего класса облегчает работу с таймером. Единственной проблемой остается достаточно сложное и возможно непонятное конечному пользователю описание заголовка Callback функции TimerProc. Чтобы облегчить ее решение, можно, как это сделано в нашем примере, заготовку этой функции включить в описание класса в качестве комментария.
В заключение приведем результаты эксперимента с нажатием кнопок Start1 и Finish1:
Создан Таймер: Идентификатор =31711 Hi 1 Hi 2 Hi 3 Удален Таймер: Идентификатор =31711 Создан Таймер: Идентификатор =31704 Hi 4 Hi 5 Hi 6 Hi 7 Удален Таймер: Идентификатор =31704
На этом мы закончим рассмотрение темы работы с функциями Win32 API.