Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Как объединить несколько таймеров TTimer в один компонент в Lazarus и Free Pascal

Delphi , Компоненты и Классы , TTimer

 

В Lazarus и Free Pascal, как и в Delphi, компонент TTimer часто используется для выполнения периодических задач. Иногда возникает необходимость управлять большим количеством таймеров, что может привести к загромождению кода и его дублированию. В этой статье мы рассмотрим, как объединить несколько таймеров в один компонент, упростив структуру вашего приложения.

Проблема:

Представьте, что у вас есть приложение, где требуется реализовать несколько независимых таймеров, каждый из которых отвечает за свою задачу (например, обновление данных, анимация, проверка состояния соединения и т.д.). Использование отдельных компонентов TTimer для каждой задачи приводит к:

  • Раздуванию кода: Код для настройки и управления каждым таймером дублируется.
  • Усложнению поддержки: Изменения в логике работы таймеров необходимо вносить в нескольких местах.
  • Сложности масштабирования: Добавление новых таймеров требует добавления новых компонентов и соответствующего кода.

Решение:

Основная идея заключается в создании класса, который инкапсулирует в себе несколько таймеров TTimer и предоставляет удобный интерфейс для управления ими. Рассмотрим пример реализации:

unit TimerUnit;

{$mode objfpc}{$H+}

interface

uses
  SysUtils, Classes, ExtCtrls;

type
  // Тип процедуры-обработчика события таймера
  TTimerEvent = procedure(Sender: TObject) of object;

  // Класс, управляющий несколькими таймерами
  TMultiTimer = class(TComponent)
  private
    FTimers: TList; // Список таймеров
    FEnabled: Boolean; // Общее состояние таймеров

    // Внутренний класс для представления таймера
    TTimerInfo = class(TObject)
    public
      Timer: TTimer;
      Interval: Integer;
      OnTimerEvent: TTimerEvent;
    end;

    procedure TimerEvent(Sender: TObject); // Обработчик события таймера

  protected
    procedure SetEnabled(Value: Boolean);
    virtual procedure Notification(AComponent: TComponent; Operation: TOperation); override;

  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    // Добавление нового таймера
    procedure AddTimer(Interval: Integer; OnTimer: TTimerEvent);

    // Удаление таймера
    procedure RemoveTimer(Index: Integer);

    // Запуск всех таймеров
    procedure Start;

    // Остановка всех таймеров
    procedure Stop;

    // Свойства
    property Enabled: Boolean read FEnabled write SetEnabled;
  end;

implementation

{ TMultiTimer }

constructor TMultiTimer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FTimers := TList.Create;
  FEnabled := False;
end;

destructor TMultiTimer.Destroy;
var
  i: Integer;
begin
  Stop;
  for i := 0 to FTimers.Count - 1 do
  begin
    TTimerInfo(FTimers[i]).Timer.Free;
    TTimerInfo(FTimers[i]).Free;
  end;
  FTimers.Free;
  inherited Destroy;
end;

procedure TMultiTimer.AddTimer(Interval: Integer; OnTimer: TTimerEvent);
var
  TimerInfo: TTimerInfo;
begin
  TimerInfo := TTimerInfo.Create;
  TimerInfo.Timer := TTimer.Create(Self); // Важно: Owner - Self, чтобы таймер уничтожался вместе с компонентом
  TimerInfo.Timer.Interval := Interval;
  TimerInfo.Timer.OnTimer := TimerEvent;
  TimerInfo.Interval := Interval;
  TimerInfo.OnTimerEvent := OnTimer;
  FTimers.Add(TimerInfo);
  if FEnabled then
    TimerInfo.Timer.Enabled := True;
end;

procedure TMultiTimer.RemoveTimer(Index: Integer);
var
  TimerInfo: TTimerInfo;
begin
  if (Index >= 0) and (Index < FTimers.Count) then
  begin
    TimerInfo := TTimerInfo(FTimers[Index]);
    TimerInfo.Timer.Free;
    TimerInfo.Free;
    FTimers.Delete(Index);
  end;
end;

procedure TMultiTimer.Start;
var
  i: Integer;
begin
  FEnabled := True;
  for i := 0 to FTimers.Count - 1 do
  begin
    TTimerInfo(FTimers[i]).Timer.Enabled := True;
  end;
end;

procedure TMultiTimer.Stop;
var
  i: Integer;
begin
  FEnabled := False;
  for i := 0 to FTimers.Count - 1 do
  begin
    TTimerInfo(FTimers[i]).Timer.Enabled := False;
  end;
end;

procedure TMultiTimer.TimerEvent(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to FTimers.Count - 1 do
  begin
    if TTimerInfo(FTimers[i]).Timer = Sender then
    begin
      TTimerInfo(FTimers[i]).OnTimerEvent(Self); // Передаем Self как Sender
      Break;
    end;
  end;
end;

procedure TMultiTimer.SetEnabled(Value: Boolean);
begin
  if FEnabled <> Value then
  begin
    if Value then
      Start
    else
      Stop;
  end;
end;

procedure TMultiTimer.Notification(AComponent: TComponent; Operation: TOperation);
var
  i: Integer;
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (AComponent = Owner) then
  begin
    // Освобождаем ресурсы, если владелец (форма) уничтожается
    for i := 0 to FTimers.Count - 1 do
    begin
      TTimerInfo(FTimers[i]).Timer.Free;
      TTimerInfo(FTimers[i]).Free;
    end;
    FTimers.Free;
  end;
end;

end.

Пояснения к коду:

  • TMultiTimer - класс, представляющий наш компонент, управляющий несколькими таймерами. Он наследуется от TComponent, чтобы его можно было разместить на форме.
  • FTimers: TList - список, хранящий информацию о каждом таймере.
  • TTimerInfo - внутренний класс, содержащий экземпляр TTimer, интервал, и обработчик события.
  • AddTimer - добавляет новый таймер в список. Важно указать Self в качестве владельца таймера (TTimer.Create(Self)), чтобы таймер был автоматически уничтожен вместе с компонентом TMultiTimer.
  • RemoveTimer - удаляет таймер из списка.
  • Start и Stop - запускают и останавливают все таймеры, соответственно.
  • TimerEvent - общий обработчик события OnTimer для всех таймеров. Он определяет, какой именно таймер вызвал событие, и вызывает соответствующий обработчик.
  • SetEnabled - устанавливает общее состояние таймеров (включены или выключены).
  • Notification - переопределенный метод, который обрабатывает уведомления об уничтожении владельца компонента (например, формы). Это необходимо для освобождения ресурсов, выделенных для таймеров.

Пример использования:

uses
  ..., TimerUnit;

type
  TForm1 = class(TForm)
    MultiTimer1: TMultiTimer;
    Label1: TLabel;
    Label2: TLabel;
  private
    procedure Timer1Tick(Sender: TObject);
    procedure Timer2Tick(Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Timer1Tick(Sender: TObject);
begin
  Label1.Caption := DateTimeToStr(Now);
end;

procedure TForm1.Timer2Tick(Sender: TObject);
begin
  Label2.Caption := IntToStr(Random(100));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MultiTimer1 := TMultiTimer.Create(Self);
  MultiTimer1.AddTimer(1000, Timer1Tick); // Обновление времени
  MultiTimer1.AddTimer(500, Timer2Tick);  // Генерация случайного числа
  MultiTimer1.Enabled := True; // Запускаем все таймеры
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  MultiTimer1.Free;
end;

В этом примере мы создаем экземпляр TMultiTimer на форме и добавляем два таймера: один для обновления времени в Label1, а другой для генерации случайного числа в Label2.

Альтернативное решение:

Вместо использования TList для хранения информации о таймерах, можно использовать TObjectList с указанием параметра True в конструкторе. Это позволит автоматически освобождать память, занимаемую объектами TTimerInfo при удалении их из списка. Например:

FTimers := TObjectList.Create(True); // Автоматическое освобождение объектов

В этом случае, в деструкторе TMultiTimer не нужно явно освобождать память, занимаемую объектами TTimerInfo.

Преимущества использования TMultiTimer:

  • Централизованное управление: Все таймеры управляются из одного места.
  • Уменьшение дублирования кода: Код для настройки и управления таймерами инкапсулирован в классе TMultiTimer.
  • Упрощение поддержки: Изменения в логике работы таймеров вносятся в одном месте.
  • Улучшение масштабируемости: Добавление новых таймеров требует только добавления новых записей в список таймеров.

Заключение:

Использование компонента TMultiTimer позволяет значительно упростить структуру приложений, требующих использования нескольких таймеров. Этот подход позволяет централизованно управлять таймерами, уменьшить дублирование кода и упростить поддержку и масштабирование приложения. Предложенный пример кода можно адаптировать и расширить в соответствии с потребностями вашего проекта.

Создано по материалам из источника по ссылке.

В Lazarus и Free Pascal можно объединить несколько таймеров TTimer в один компонент, создав класс, который инкапсулирует таймеры и предоставляет централизованное управление ими, уменьшая дублирование кода и упрощая поддержку.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: TTimer ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-09-14 16:48:49/0.0067689418792725/0