Blog. Just Blog

Splash-окно при загрузке программы

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
При запуске некоторых приложений иногда требуется выполнить какие-нибудь ресурсоемкие или продолжительные по времени действия, например, загрузка дополнительных модулей, сбор информации о системе, распаковка файлов данных и т.п. Часто во время таких процессов открывается так называемое splash-окно (его также называют "сплэш-окно" или сокращенно "сплэш"), то есть модальное окно без заголовка, расположенное по центру экрана, обычно с логотипом и названием программы. Также в нем меняющейся строкой отображается текущее действие программы, и, иногда, полоса прогресса выполнения. Таким образом пользователя как бы уведомляют, что программа не зависла при запуске, а просто выполняет нужные ей действия и надо немного подождать. После появления главного окна программы сплэш закрывается. Попробуем сделать что-нибудь подобное на Ассемблере.

Сперва нарисуем само окно. Оно должно быть без заголовка, модальное, можно разместить на нем картинку-логотип. Для большего эффекта добавим на это окно прогрессбар и текстовое поле для отображения состояния загрузки.
  1. ; Стиль прогрессбара - непрерывный бегунок. В FASM значение не определено,
  2. ; сделаем это самостоятельно
  3. PBS_MARQUEE = 8
  4.  
  5. dialog demonstration,' Splash Demo',0, 0, 150, 60,\
  6.     WS_POPUP+DS_CENTER+DS_SYSMODAL+WS_BORDER, WS_EX_TOOLWINDOW,0,'Arial',10
  7.   dialogitem 'STATIC',1, 1, 0, 0, 138, 38 ,WS_VISIBLE+SS_BITMAP
  8.   dialogitem 'STATIC','Loading...',ID_TEXT, 0, 34, 150, 8 ,WS_VISIBLE+SS_CENTER
  9.   dialogitem 'msctls_progress32', '', IDC_PROGRESS, 3, 47, 145, 10,\
  10.     WS_VISIBLE+PBS_MARQUEE
  11.   dialogitem 'BUTTON','',IDCANCEL, 0, 0, 0, 0, 0
  12. enddialog
Несколько комментариев к коду. Прогрессбар задается в ресурсах как элемент диалогового окна msctls_progress32 со стилем PBS_MARQUEE, то есть он будет непрерывно двигаться. Если требуется указание более точного процента выполнения загрузки, то придется обратиться к документации. Скрытая кнопка EXIT предназначена для того, чтобы splash-окно можно было закрыть при помощи клавиши Esc. Как правило, разработчики пренебрегают возможностью закрывать сплэш по желанию пользователя, и посреди экрана висит уродливое окно, которое нельзя ни закрыть, ни передвинуть, пока приложение не загрузится. Никогда так не делайте! Также обратите внимание, чтобы заработал такой прогрессбар, должна быть вызвана функция InitCommonControls, а исполняемый файл должен содержать соответствующий манифест.

Переходим к программированию. Чтобы открытое splash-окно не мешало выполнению основного приложения, его надо запускать в отдельном потоке в самом начале программы:
  1. ; Запустить splash-окно отдельным потоком
  2. xor     eax,eax
  3. push    eax
  4. invoke  CreateThread,NULL,NULL,SplashProc,NULL,NULL,esp
  5. pop     eax
  6.  
  7. ...
  8.  
  9. ;---------------------------------------------
  10. ; Процедура открытия splash-окна отдельным потоком
  11. ;---------------------------------------------
  12. proc SplashProc hwnd:DWORD
  13.         ; Показать сплэш-окно
  14.         invoke  DialogBoxParam,[hInstance],1,HWND_DESKTOP,DialogProc,0
  15.         ret
  16. endp
Процедура обработки окна DialogProc, в принципе, мало отличается от обычных обработчиков окон. Обязательно добавьте в него код для перетаскивания окна за любое место, если приложение грузится мучительно долго, то пользователь хотя бы сможет поразвлекаться, перетаскивая мышкой сплэш-окно по экрану. Про возможность принудительного закрытия я уже говорил.

Остался последний вопрос - как осуществить взаимодействие приложения со сплэш-окном, а именно передача строки текущего состояния, установка процента выполнения на прогрессбаре (если выбран такой вариант реализации) и как закрыть сплэш-окно из главного приложения. Для всего этого есть несколько способов, я сделал такой. В обработчике splash-окна устанавливается таймер, например, на интервал 10 миллисекунд. В памяти приложения устанавливаются глобальные переменные: текстовая строка сообщения с текущим состоянием, процент выполнения (если требуется) и флаг необходимости закрытия окна. Основное приложение выполняет свою загрузку, периодически записывая в строку текущее состояние и процент, а после загрузки взводит флаг необходимости закрытия сплэша. Обработчик сплэша по таймеру считывает строку состояния и процент выполнения, и на основании этих данных устанавливает соответствующие значения у себя. Если установлен флаг закрытия, то окно сплэша закрывается.

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

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Splash.Screen.Demo.zip (7,947 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 4542 | Комментариев: 10

Метки: Assembler, окна
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (04.04.2011 в 14:50):
Можно субклассировать и прогрессбар, была бы необходимость.
Isaev (04.04.2011 в 14:49):
Приятное окошко! Поучительно.
В общем таскаться Splash-окну и не обязательно, но раз таскается, надо было сделать чтобы и за ProgressBar тоже цеплялось )
ezfalc0n (03.04.2011 в 21:42):
уточнение: посты ниже адресовал 64-ядерный процессор. "Сплэш-окно при загрузке программы" и что-то вроде "Защищенное сплэш-окно" разные темы. Могу представить, если б, Дима, тебе пришлось при написании статьи учитывать все "а вдруг" и "а если" - этоб по книге было на каждую тему. Колесо дали - а велосипед, уж извольте, сами =)
ezfalc0n (03.04.2011 в 05:04):
Насчет взаимодействия можно конечно использовать обмен сообщениями WM_USER+message между процедурами. Или, если необходимо знать как дела  у потока, можно обязать его обновлять глобальную переменную счетчик "ticker". На всякий случай, для cpp - переменную определять через volatile.

Дима, спасибо - понастальгировал
ezfalc0n (03.04.2011 в 04:52):
Подобная картинка генерится на ходу, без особых затрат, через CreateFontEx, BitBlt и иже с ними. Можно еще анимацию в стиле plasma/flame и т.д. добавить. Также можно хранить ее в адаптированном RLE, места будет занимать немного.
ManHunter (30.03.2011 в 20:50):
Ну в общем это и имелось в виду. И ладно на шару, хуже если на продажу :)
64-ядерный процессор (30.03.2011 в 19:41):
ManHunter, на счёт "какой-нибудь мудила" - не знаю, а вот то что всякие ублюдки будут выставлять прогу на шару и при этом вставлять свой левый логотип - это точно.
ManHunter (30.03.2011 в 18:06):
Можно и так. Но в этом случае придется добавлять обработчик ошибок, если вдруг картинка куда-то потерялась, и непонятно что рисовать в сплэше в случае такой ошибки. Плюс обязательно найдется какой-нибудь мудила, который заменит ее на свой логотип. Так что хранить в ресурсах удобнее, надежнее и проще всего.
zummenix (30.03.2011 в 18:03):
Чтобы не держать бмпешку в ресурсах можно загружать ее функцией LoadImage и удалять при закрытии сплэш-окна.
1 (30.03.2011 в 14:22):
Спасибо, занятно.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0046 сек.) / Память: 4.5 Mb
Наверх