Вы здесь

CA-Visual Objects: как сделать окно ожидания

Окно ожидания

 

 

 

 

 

 

Времени на написание больших статей сейчас нет, поэтому решил поделиться наработкой. Наработка простая, но полезная – о том, как сделать окно ожидания. О чём это я?

 

Давайте посмотрим, как работает пользователь. Он что-то нажимает и что-то начинает работать. Понятно, нажатием кнопочки, пользователь запускает нужный процесс (расчёт, выгрузку, загрузку и пр.). Этот процесс выполняется не сиюминутно. Поэтому, перед его запуском нормальный программист делает защиту от случайного повторного запуска, от запуска недопустимых параллельных процессов и, если он длителен – как-то скрашивает ожидание пользователя.

 

CA-Visual Objects – небогатая среда разработки. Почему так вышло – отдельная тема. Поэтому каждый выкручивается, как может. Стандартный набор действий: после нажатия кнопки (на форме окна), её делают серой (Disable) и меняют курсор «мышки» на песочные часы. Когда всё заканчивается – возвращают прежний курсор и доступ к нажатию кнопки (Enable).

 

Но этого недостаточно, так как изменение формы курсора не приводит к запрету пользования «мышкой» и клавиатурой. Поэтому, за время выполнения запущенного процесса пользователь может успеть нащёлкать по десятку кнопочек, подёргать меню… И, правильно, мгновенно по окончанию работы текущего процесса – начнут отрабатываться все нажатия, которые успел сделать пользователь.

 

«Продвинутые» программисты об этом догадываются и пытаются при нажатии какой-либо кнопочки позапрещать всё, что может помешать. Но всё ли получиться так, как хотелось? А если что-то забудется? А если что-то кардинально поменяется – что всё переделывать, снова садиться и думать что и после чего должно или не должно работать? Короче, сплошные проблемы…

 

А как должно быть? Пользователь нажал кнопку, запустился процесс, и пока он идёт – он может нажимать всё, что ему угодно, но ничего из этого срабатывать не должно. А ещё – хочется красивой картинки, в виде идущих часиков или секундомера J.

 

Вот это мы сейчас и сделаем.

 

Для начала нам нужно окно. Какое? Такое, чтобы пока оно «висит» на экране нельзя было работать ни с чем, кроме него. Оно должно быть всегда по центру на переднем плане, неизменяемое в размерах и с картинкой ожидания (часики). Его можно сделать без заголовка и без возможности перемещения.

 

Есть ли подходящее окно в CA-Visual Objects? Есть – это DialogWindow. Так и поступаю: делаю новый модуль, в нём создаю DialogWindow-окно под названием «WinWatch». Внимание: установку Modeless переводить в режим «TRUE» не надо! Просто сделали пустое окно с настройками по-умолчанию, как есть. Кому нравится – выставляем показ окна посредине экрана (Position: Center).

 

Теперь, неплохо бы его и доработать… Тут мне пригодилась статья Vander Nunes «Работа с регионами в Visual C++» И я сделал в PostInit() моего окна – следующее:

 

// Изменяем стиль окна (избавляемся от заголовка)

 

            dwStyle := GetWindowLong( SELF:Handle(), GWL_STYLE )

 

dwStyle := dwStyle + _AND( dwStyle, WS_CAPTION )

dwStyle := dwStyle + _AND( dwStyle, WS_SIZEBOX )

 

            SetWindowLong( SELF:Handle(), GWL_STYLE, dwStyle )

 

  // Перерисовываем окно, а так же убираем рамку окна, чтобы

  // нельзя было менять его размер

 

InvalidateRect( SELF:Handle(), NULL, TRUE )

SetWindowPos( SELF:Handle(), NULL, 0, 0, 100, 100, SWP_NOMOVE + SWP_NOZORDER )

 

Так, теперь немного подумаем. Если запустится это окно, то оно ничего не даст делать, а как же наш процесс? Ну, тут сразу народ кидается переводить окно в режим «Modeless» и… За что боролись, на то и напоролись. Наша песня хороша – начинай сначала.

 

В режим «Modeless» переводить нельзя! А правильно будет – запустить нужный процесс параллельно! Как это сделать? Есть такая хорошая книжка: Sandy Hood и Alwyn Jennings-Bramly «Exploring CA-Visual Objects 2.5». Книжка древняя, но толковая. Посмотрим в главу 23 «One at a Time Please? Not any More!» (в русском переводе в и-нете она называется «Многопоточность»). Как там было сказано, так я и сделал:

 

METHOD Test( ) AS VOID PASCAL CLASS StandardShellWindow

            //

 

LOCAL dwThreadID AS DWORD

LOCAL oWin AS WinWatch

 

CreateVOThread(NULL_PTR, 0, @NewThreadWindow(), PTR(_CAST, SELF), 0, @dwThreadId)

 

oWin := WinWatch{ SELF }

oWin:Show()

 

RETURN

 

Т.е., открыл новый поток, и в нём в методе NewThreadWindow() я поместил свой «длительный» процесс. А в основном потоке – открыл своё окно ожидания.

 

Если кто внимательно почитает эту главу дальше, то увидит, что авторы жалуются, что у них возникли какие-то ошибки… Ничего страшного, ещё более внимательные и опытные читатели могут заметить, что большинство ошибок у них (у писателей этой книги) возникают из-за некоторой небрежности написания кода, которую позволяли более ранние версии CA-Visual Objects. Если всё делать правильно – ошибок не будет!

 

Так, идём дальше. Окно – это хорошо, а где же картинка? Мы её найдём в интернете или нарисуем сами. Для рисования я использовал IconLover и Easy GIF Animator. Нашёл подходящую заготовочку рисунка часов и доработал «напильником».

 

Вопрос: но я же хотел анимацию (изменяющуюся картинку), как сделать? Стандартно, из-за бедности инструментов, из анимации в CA-Visual Objects работает только «AVI». Понятно, что не каждый «AVI» есть «AVI», подходящий по формату. Плюс, если «загнать» его в ресурсы – это большой файл. Короче, кто боится идти дальше – пусть остаётся.

 

Есть другой хороший формат – «GIF»-анимация. Вот! И файлик маленький и красиво J. Вся эта красота работает с Win2K и старше с помощью дополнительной .dll-ки «GdiPlus.dll». При этом, стандартно, в Win2K её нет, но её легко добавить, скачав с официального сайта MicroSoft. Т.к. я использую CA-Visual Objects 2.7 и старше (а приложения, сделанные в них, нормально работают в среде Win2K и выше), то я остановился на формате «GIF». Если Вы используете более ранние версии CA-Visual Objects и среду Win9х-МЕ, то Вам придётся использовать или статическую картинку или формат «AVI».

 

И так, я сделал движущуюся картинку «Watch48.gif» размером 48х48. Теперь, как показать её?

 

Был у меня хороший знакомый Игорь Калиняк (если не ошибаюсь, в далёком 2004-ом году он работал в компании «Галка» в славном городе Львов). Вот он, с товарищем, собрали наработки на Си и перенесли их в КаВо, сделав свою .dll-ку «VO27aImg.dll». Созданный ими класс позволяет работать с более «продвинутыми» форматами, в том числе и с «GIF»-анимацией.

 

Скачать сие чудо можно Отсюда. Очень жаль, что Игорь «потерялся», да я и сам менял место работы, а когда попытался восстановить переписку – с его адреса уже никто не ответил. Но сделал он большое дело! Он поступил умно: его класс является производным от стандартного класса «Control», поэтому (хотя и рекомендуется для CA-Visual Objects 2.7), эта библиотека работает и в версии CA-Visual Objects 2.8 J.

 

Теперь я подключил требуемую библиотеку. На окно я поместил новый контрол «ikImage» (из библиотеки Игоря) размером чуть больше чем 48х48 (размер моей картинки), и дал ему название «ikImageFile». (Если Вы используете «AVI»-файл, то можете использовать стандартный «Animation Control»). И прописал ресурс: RESOURCE WATCH48 GIF D:\CavoApp\Waiter\Watch48.gif

 

Что ж, теперь снова возвращаемся в PostInit() нашего окна и дописываем:

 

pszResName := PSZ( _CAST, "WATCH48" )

pszResType := PSZ( _CAST, "GIF" )

            IF SELF:oDCikImageFile:LoadResource( _GetInst(), pszResName, pszResType )

 

                        SELF:oDCikImageFile:ImageDraw()

            ENDIF

 

Ну вот, вроде бы и всё… Стоп, не всё! Картинка-то выйдет квадратной, а хочется просто тикающих часиков J. Ясно, идём навстречу! Тут же дописываем:

 

// Создаём круглый регион

hRegion1 := CreateEllipticRgn( 27, 27, 75, 75 )

 

// Исключаем область заголовка и бордюров

OffsetRgn( hRegion1, ;

            GetSystemMetrics( SM_CXBORDER ) * 4, ;

            GetSystemMetrics( SM_CYCAPTION ) + GetSystemMetrics( SM_CYBORDER ) * 4 )

 

// Прикрепляем регион к окну

SetWindowRgn( SELF:Handle(), hRegion1, TRUE )

 

// Удаляем объект региона

DeleteObject( hRegion1 )

 

Теперь, точно всё J. Запускаем – работает!!!

 

12.01.2012г. Карандаш.

 

Комментарии

Края у часов не гладкие
Есть какие-то средства загладить? А что с прозрачностью?
Хочу демку, демку давай!

Демку Вы и сами напишите. А вот, насчёт прозрачности мне интересно Вас послушать :))

И какой такой факт навел на данные нестандартные строки?

Факты изложены. Что не нравится? Ваши предложения?

Очень заинтересовала данная тематика, оригинальный взгляд.

Да, время от времени, я занимаюсь "изобретением велосипеда" :))
Сейчас отрабатываю ещё одну "велосипедную" тематику, так что - ждите!

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer