В этой статье я хочу рассказать о том, как можно в программе реализовать свой собственный прогресс-бар. Пригодится это может в случае, если вам не нравятся стандартные варианты или вообще нет возможности сделать его обычными средствами.
Очень надо
Одно время я работал над системой обработки данных для построения огромного количества графиков, отчетов и получения статистики.
В качестве источника данных использовалась БД. Пользователь запускал приложение, выбирал нужный отчет или график, заполнял входные данные и генерировалась красивая 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