Мыльные пузыри в Delphi #4. Часть финальная
Опубликовано 31.08.2011 г. 23:04
Заключительная статья про реализацию "имитации" заставки Windows "Мыльные пузыри". В основном здесь речь пойдет о том, как сделать из исполняемого exe-файла "настоящую" scr-заставку.
Прежде чем перейду к описанию заставки, вернусь к вопросу производительности. Изначально при рисовании с использованием слоев загрузка процессора была 40%, после того как были убраны слои, и рисование стало основано на маске прозрачности, накладываемой на градиентный круг, загрузка упала до 20%. В текущей версии загрузка составляет 2-3%. Сделано это с помощью такой манипуляции - раньше маска прозрачности пузыря применялась к градиентному кругу. На самом деле изначально я хотел делать градиент цвета при заливке круга, но при реализации получилось что там цвет один, только в нижней части круга он более прозрачный. Так что это по сути была сплошная заливка с маской прозрачности. К этому виду я ее и привел. Теперь рисование проводится с помощью сплошной кисти, а в маску пузыря добавляется еще и градиентная прозрачность. Для достижения такого эффекта были вновь добавлены слои. Т.е градиентная маска применяется к слою, а затем на слое рисуется сама маска пузыря. Также была убрана обводка пузыря (отрисовка окружности после применения маски). Тут весьма интересная особенность: если каждый раз делать эту обводку (DrawGeometry(ID2D1EllipseGeometry)), то загрузка повышается то 8-10%. Странно, казалось бы просто рисование окружности. Зато обводка была добавлена в маску прозрачности. В маске я аналогично отрисовал окружность с непрозрачным цветом. Так же в текущей версии цвета пузыря меняются не в полете при касаниях об стенку, а раз в полсекунды (Здесь для анимации используются т.н key-frames - TUIAnimationKeyframe, для того чтобы в StoryBoard добавить изменения цвета последовательно). Ну а теперь вернемся к формированию заставки. Весьма логично предположение, что scr-заставка является обычным ехе-приложением. И это действительно так. Так что для начала изменим расширение исполняемого файла. Сделать это можно в меню Project -> Options -> Application -> Target file extension, либо директивой {$E scr} в dpr-файле проекта. Оба варианта равносильны. При разработке и тестировании заставки вы столкнетесь с тем, что заставку надо поместить в директорию System32. Сделать это можно несколькими путями. Но очевидный метод, предназначенный специально для таких целей, это Build Events. В меню Projects -> Options -> Build Events надо задать Post-Build команду:

copy $(OUTPUTPATH) $(WINDIR)\System32\$(OUTPUTFILENAME) /yкоторая скопирует выходной файл OUTPUTPATH (полное имя) в системную папку. При необходимости ключом /y будет проведена перезапись файла. Наверное, стоит отметить, что до выхода Delphi 2010 подобная возможность (Build Events) отсутствовала, а в Delphi XE она была расширена и доработана, так что выглядит иначе. По сему, если вы не можете использовать Build Events, вы можете настроить output dir для файла в свойствах сборки проекта. Когда ваша заставка попала в системную директорию, вы можете открыть окно выбора экранных заставок (Персонализация - Заставка). Здесь вы заметите, что в списке ваша заставка перечислена по имени файла. Хотя все другие заставки имеют нормальное описание. Совсем немного поисков в интернете и вы найдете целую кучу ссылок говорящую о том, что надо включить описание в заголовок ехе-файла, используя директиву {$D} или {$DESCRIPTION} с текстом 'SCRNSAVE : Ваше название'. Возможно все это работало 10 лет назад, но сейчас эти манипуляции бесполезны. Таким путем результат вы не получите. Нам необходимо подключить ресурсный файл, в котором описать строку с названием. Для этого мы создаем текстовый файл а-ля myres.rc и подключаем его к проекту. В файле необходимо описать строковую таблицу и строку с идентификтором 1, например, так:
stringtable begin 1 "Delphi bubbles Direct2D"; end;Вообще мы должны знать, что подобное описание строк в ресурсах было заменено на определение resourcestring. Но я так и не понял как их использовать для наших целей, так что видимо никак. Если вы уже скопировали заставку в нужную директорию, и пробовали открыть окно настройки, то наверняка заметили, что при выборе пункта меню с вашей заставкой она запускалась. Есть несколько возможных вариантов запуска заставки.
- При настроке (контекстное меню файла) заставка запускается без параметров.
- При использовании кнопки Настройка в окне выбора заставки мы получаем параметры командной строки в таком виде: /c:HWND, где hwnd - дескриптор окна, поверх которого надо модально показать диалог настройки.
- Наверное вы замечали, что в окне выбора заставки, есть маленькое окошко предпросмотра, в котором рисуется ваша заставка. Так что при выборе вашей заставки в списке в качестве активной, она запускается с параметрами /p HWND. Заметьте тут два параметра, в отличие от предыдущего 1 параметра конфигурации, где дескриптор указан через двоеточие. Здесь дескриптор - окошко превью, в котором обычно и отображается уменьшенная заставка.
- Последний вариант - непосредственный просмотр заставки. Если вы нажимаете кнопку Просмотр, то заставка запускается с ключом /s. А если она запускается автоматически (согласно вашим настройкам системы), то с ключом /S.
// Parameters : // // no params -> Context menu -> Configure // /p HWND -> Install; hwnd - parent window // /c:HWND -> Configure, parent - modal // /s - view if (paramCount = 0) or ((ParamCount = 1) and (StartsText('/c:', ParamStr(1)))) then begin //showModal configuration window MessageDlg('Delphi bubbles ScreenSaver has no parameters!', mtInformation, [mbOk], 0); end else if (paramCount = 2) and (StrLower(PChar(ParamStr(1))) = '/p') then begin // set this screensaver as current // HWND - preview window HWND end else if (ParamCount = 1) and (StrLower(PChar(ParamStr(1))) = '/s') then begin Application.Initialize; Application.MainFormOnTaskbar := True; Application.Title := 'Delphi bubbles'; Application.CreateForm(TScreenForm, ScreenForm); Application.Run; end;Вот пожалуй и все, что требуется для создания вашей собственной заставки. Конечно требуется настроить заставку так чтобы она завершала работу при нажатии кнопки мыши или клавиатуры а так же при движении мыши. С последним, кстати, как ни странно у меня возникла проблема. Если форме назначить обработчик события OnMouseMove, в котором вызывается метод Close(), то почему то после запуска, и прорисовки первых нескольких кадров, работа завершается. Кажется это особо странным в свете того, что мышь лежит неподвижно, а запуск вообще производится с помощью клавиатуры. Так что тут я что то не понял :) К статье прикладываю исходный код последней версии пузырей, вместе со скомпилированным файлом: Исходный код и Exe Вид пузыриков в последнем варианте остается таким:

17.12.2011 в 00:31
здесь хорошие хедеры, я их использовал.
там только в двух файлах они, во втором - UIAnimationMS - CLSID объектов, так что для себя CLSID перенес в первый файл и все.