WinAnimationManager: Grid Layout
Опубликовано 06.06.2010 г. 21:57
Вторая статья про изучение Windows Animation Manager, где мы рассмотрим вариант реализации примера MSDN: Grid Layout Sample с использованием Delphi. Суть данного демонстрационного приложения заключается в том, что оно создает превью изображений, располагающихся в библиотеке изображений, и располагает их на форме в виде таблицы, при изменении размеров формы таблица перестраивается, с использованием анимации.
Сразу приведем изображение конечного результата, что бы вы решили хотите читать дальше или нет (:

Когда трансляция примера с VC на Delphi была почти завершена, я столкнулся с проблемой использования импортированной библиотеки типов UIAnimation.dll. И по началу я задумал было переписать заголовочный файл, но потом вспомнил про гугл, и в результате нашел сайт www.bilsen.com, автор которого кроме того что качественно переписал хэдеры, но еще и выложил полнофункциональную демку использования Windows Animation Manager (с GDI+). Поэтому скачав заголовочный файл я начал его использовать. Наш пример будет как и прежде основан на использовании Direct2D. Итак, разобьем нашу программу на 3 составных части:

Когда трансляция примера с VC на Delphi была почти завершена, я столкнулся с проблемой использования импортированной библиотеки типов UIAnimation.dll. И по началу я задумал было переписать заголовочный файл, но потом вспомнил про гугл, и в результате нашел сайт www.bilsen.com, автор которого кроме того что качественно переписал хэдеры, но еще и выложил полнофункциональную демку использования Windows Animation Manager (с GDI+). Поэтому скачав заголовочный файл я начал его использовать. Наш пример будет как и прежде основан на использовании Direct2D. Итак, разобьем нашу программу на 3 составных части:
- Класс описания preview изображения TThumbnail
- Менеджер для управления и позиционирования превью - TLayoutManager
- и непосредственно форма на которой это все будет выводится.
TThumbnail = class (TObject) strict private animationManager : IUIAnimationManager; bitmap : ID2D1Bitmap; public varX, varY : IUIAnimationVariable; filename : string; destructor Destroy(); constructor Create( pBitmap : ID2D1Bitmap; aManager : IUIAnimationManager; x,y : double); function getSize() : TD2D1SizeF; procedure Render(canvas : TDirect2DCanvas; outlineBrush : ID2D1Brush) ; end;Реализация методов класса весьма проста, при создании объекта, мы также создаем переменные vaX,varY. При отрисовке мы получаем значения переменных,и в полученных координатах рисуем изображение, потом рамку вокруг него, и затем имя файла чуть ниже. Далее очередь класса TLayoutManager. Для чего он? Допустим изображения на нашей форме выводятся в 2 строки, по 4 штуки в ряд. Уменьшив размер формы, нам потребуется перестроить порядок, например получив три строки, в первых двух будет по 3 изображения, в третьей - два. Следовательно основная функция данного класса - при изменении размеров формы рассчитать новое местоположение для всех миниатюр, и соответствующим образом настроить анимацию. Следовательно класс будет хранить все требуемые ссылки на объекты анимации - IUIAnimationManager, IUIAnimationTimer, IUITransitionLibrary. (основные экземпляры хранятся в главной форме, ибо анимация может потребоваться и не только в данном случае, но в других местах программы). Также само собой потребуется хранить список наших миниатюр, в виде TList<TThumbnail>. Пара методов для выстраивания миниатюр: основной Arrange будет определять на какой строке расположится миниатюра (по заполняемости слева направо). Второй - ArrangeRow будет выстраивать миниатюры находящиеся в одной строке. Также нам потребуется метод для создания планировщика и настройки анимации - AddThumbnailTransitions. Итого, описание класса принимает следующий вид:
TLayoutManager = class(TObject) protected AnimationManager : IUIAnimationManager ; AnimationTimer : IUIAnimationTimer ; TransitionLibrary : IUIAnimationTransitionLibrary; thumbs : TList<TThumbnail>; procedure ArrangeRow( pStoryboard : IUIAnimationStoryboard; iThumbMin,iThumbMax : integer; xRow,yRow : double; heightMax : double ); procedure AddThumbnailTransitions( pStoryboard : IUIAnimationStoryboard; pVariablePrimary : IUIAnimationVariable ; valuePrimary : double; pVariableSecondary : IUIAnimationVariable; valueSecondary : double ) ; public destructor Destroy(); constructor Create( pAnimationManager : IUIAnimationManager; pAnimationTimer : IUIAnimationTimer ; pTransitionLibrary : IUIAnimationTransitionLibrary ; uThumbCount : Cardinal; thumbsList : TList<TThumbnail> ); procedure Arrange(sizeClient : TD2D1SizeF) ; end;Теперь перейдем к описанию главной формы приложения. Канва имеет тип TDirec2DCanvas, как и ранее изменяет размер при изменении размера формы. Также перекрыта обработка сообщения WM_ERASEBKGND. Сразу напомню, что при изменении размера формы необходимо вызывать метод Arrange() менеджера миниатюр. При создании формы сделаем следующие вещи:
- Создаем канву
- Создаем главные объекты анимации
- Создаем градиентную кисть для заливки фона
- Создаем сплошную кисть, для обводки миниатюр
- Создаем список миниатюр thubms : TList<TThumbnail> и запускаем процедуру его заполнения FindImages().
- Получить интерфейс IShellItem для библиотеки изображений.
- Создаем интерфейс INamespaceWalk и с помощью него получаем массив PItemIDList для всех элементов библиотеки.
- Для всех найденных изображений, получаем интерфейс IShellItem
- с помощью метода DecodeImageFromThumbCache (описан ниже) получаем миниатюры изображений.
- Создаем объект TThumbnail и добавляем его в список.
procedure TMainForm.FindImages(); var picLib, si : IShellItem; nsWalk : INamespaceWalk; pidl : array of PItemIDList; pidlCount : Cardinal; i:integer; bitmap : ID2D1Bitmap; size : TD2D1SizeF; tItem : TThumbnail; fname : pchar; begin SHGetKnownFolderItem(FOLDERID_PicturesLibrary, KF_FLAG_CREATE, 0, IID_IShellItem, pointer(picLib)); nsWalk := CreateComObject(CLSID_NamespaceWalker) as INamespaceWalk; nsWalk.Walk( picLib,NSWF_NONE_IMPLIES_ALL,1,nil); nsWalk.GetIDArrayResult(pidlCount, PItemIdList(pidl)); for i:=0 to pidlCount-1 do begin SHCreateItemFromIDList(pidl[i],IID_IShellItem,si); DecodeImageFromThumbCache(si,bitmap); Bitmap.GetSize(size); tItem := TThumbnail.Create(bitmap,animationManager,clientWidth/2,-size.height/2 -1); si.GetDisplayName(SIGDN_PARENTRELATIVEPARSING,fname); tItem.filename := fname; thumbs.Add(tItem); end; pidl := nil; layoutManager := TLayoutManager.Create(animationManager,animationTimer,transitionLibrary,thumbs); canvas.RenderTarget.GetSize(size); layoutManager.Arrange(size); end;Получение миниатюры для заданного IShellItem объекта реализуем с помощью интерфейса IShellItemImageFactory, если объект представляет изображение, то получим миниатюру, если же это какой либо другой тип файла, то получим его иконку.
procedure TMainForm.DecodeImageFromThumbCache(item: IShellItem; var bitmap: ID2D1Bitmap); const size : TSize = (cx : 96; cy : 96); var ImageFactory :IShellItemImageFactory; hBm : HBitmap; tBm : TBitmap; begin item.QueryInterface(IID_IShellItemImageFactory,imageFactory); imageFactory.GetImage(size,0,hBm); tBm := TBitmap.Create; tBm.Handle := hBm; bitmap := canvas.CreateBitmap(tBm); imageFactory := nil; tBm.Free(); end;Использование данного метода может тормозить программу, поэтому его не рекомендуется использовать в главном потоке. Собственно вы запросто в этом убедитесь если в вашей библиотеке изображений будет несколько сотен картинок. Полный исходный код можно посмотреть здесь [Спасибо Алексею Тимохину за подкинутую ссылку на SkyDrive :)]. Заголовочный файл UIAnimation, взятый по ссылке указанной в начале статьи прилагается. Единственное, что в файл были добавлены идентификаторы классов (в оригинале они были расположены в отдельном файле).
27.01.2013 в 00:46
28.01.2013 в 02:15
по скорости особо не с чем сравнивать, вроде неплохо было.
31.07.2017 в 22:54
I found a sea shell and gave it to my 4 year old daughter and said "You can hear the ocean if you put this to your ear." She
put the shell to her ear and screamed. There was a hermit crab inside and it pinched her ear.
She never wants to go back! LoL I know this is totally off topic but I had to tell someone!