Внешний прогресс-бар

в 18:41, , рубрики: Delphi, dll, Программирование, прогресс-бар, метки: , ,

В этой статье я хочу рассказать о том, как можно в программе реализовать свой собственный прогресс-бар. Пригодится это может в случае, если вам не нравятся стандартные варианты или вообще нет возможности сделать его обычными средствами.

Внешний прогресс бар

Очень надо

Одно время я работал над системой обработки данных для построения огромного количества графиков, отчетов и получения статистики.
В качестве источника данных использовалась БД. Пользователь запускал приложение, выбирал нужный отчет или график, заполнял входные данные и генерировалась красивая html страничка с отчетом. Для создания системы использовался этакий «конфигуратор» со скриптовым языком. Его возможности были весьма скудными: практически нельзя было менять GUI (он строился автоматически), да и сам скриптовый язык оставлял желать лучшего.

Как-то утром состоялся у нас с менеджером примерно такой разговор:

Менеджер: Можем ли мы сделать прогресс-бар для отчетов?
Программисты: Эмм… нет, ты же знаешь, в плане интерфейса мы ничего не можем сделать.
Менеджер: Ммм… Но заказчику очень надо! ©
Программисты: Оукей, мы подумаем, что можно сделать. ©

Надо сказать, что прогресс-бар был действительно нужен. Пользователь тыкал кнопочку ОК и ждал. Ждал неопределённое время. Может 3 секунды, а может и 15 минут. В статусной строке автоматически выводились кое-какие данные, но по ним совершенно нельзя было понять, на какой стадии сейчас прогресс. Собственно, если бы не этот дурацкий кофигуратор, мы бы уже давно что-нибудь сделали.

Поиски

Первым делом, естесственно, мы стали мучать наш конфигуратор и усиленно читать справку к нему — не пропустили ли мы чего? Нет, не пропустили. Действительно, встроенной возможности создать прогресс-бар не было. Зато можно использовать WinAPI, подключать библиотеки. Только зачем?
Попробовал для интереса вызвать MessageBox из User32.dll. Работает.
И тут я подумал, что DLL ведь может содержать не только код, но и ресурсы, например, окна. А в окне уже может быть что угодно, и прогресс-бар в том числе. Если у окна убрать border и сделать так, чтобы прогресс-бар занимал основную площадь, должно неплохо получится.

Форма в DLL

Итак, нам нужно сделать свою DLL с формой внутри.
Что мы будем с этим окном делать? Очевидно, показывать окно, какое-то время менять прогресс и закрывать окно. Вот и три будущих функции.

ShowProgressBar
Создаём форму и показываем её пользователю.
Одновременно можно показывать только одно такое окно, так что стоит добавить соответствующую проверку.

UpdateProgressBar
В этой функции будет менятся текущий прогресс, вызываться она будет из цикла.
Прогресс-бару будет присваиваться новое текущее значение прогресса.

CloseProgressBar
Закрываем и убиваем окно.

Код и дизайн

В качестве IDE для простоты был выбран Delphi. Через 15 минут уже был готов «скелет» библиотеки.
На форме также было добавлено текстовое поле для пояснения текущей стадии прогресса.

Вот что у меня получилось:

Внешний прогресс бар

Другой вариант оформления — в начале статьи.

И основной код:

function ShowProgressBar(AppHandle: Cardinal; Range: Integer; Title: string): Cardinal;
begin
  if MainForm = nil then
  begin
    Application.Handle := AppHandle;
    MainForm := TMainForm.Create(Application);
    MainForm.Gauge1.MaxValue := Range;
    MainForm.Label1.Caption := Title;
    MainForm.Show;
  end;
  result := MainForm.Handle;
end;

function UpdateProgressBar(NewPosition: Integer; NewTitle: string): Integer;
begin
  if MainForm <> nil then
  begin
    MainForm.Gauge1.Progress := NewPosition;
    MainForm.Label1.Caption := NewTitle;
    MainForm.Label1.Update;
  end;
end;

function CloseProgressBar: Integer;
begin
  FreeAndNil(MainForm);
end;

Всё просто.

Не забудьте в обработку ошибок добавить вызов CloseProgressBar, там где надо. Иначе, если произойдет ошибка после ShowProgressBar, окно с прогресс-баром так и останется висеть. Кстати, его можно будет закрыть и вручную, по Alt + F4, т.к. это обычное окно.

Понятно, что у такого подхода есть один жирный минус — это костыли лишняя зависимость от DLL. Да и подключать DLL только ради какого-то прогресс-бара может показаться «жирным». Однако, в нашем случае мы без проблем могли себе это позволить. Ну а самый большой плюс — полная свобода в плане дизайна и кода. Заказчик остался очень доволен.

Ссылки по теме
Add Forms in a Delphi DLL
Как использовать форму из DLL (Delphi)

Автор: fixer_m

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js