| Недавно во время работы над проектом я столкнулся с ситуацией сохранения серии изображений в списке изображений (TImageList) в указанный файл или двоичный поток, чтобы их можно было динамически восстанавливать при необходимости. Поэтому я искал свойства и методы, связанные с классом TImageList, в справке Delphi. К сожалению, Delphi не предоставила методы SaveToFile и SaveToStream в TImageList. Поэтому, учитывая текущие ограничения TImageList, для расширения класса TImageList необходимо использовать другие методы. функции TImageList для удовлетворения реальных потребностей проекта. |
| Решение |
| Способ первый: |
| Используйте функции API ImageList_Write и ImageList_Read. В обоих случаях необходимо указать параметр типа IStream. Функция первого — сохранить список изображений указанного дескриптора в двоичный поток типа IStream; вторая — прочитать первоначально сохраненный список изображений из двоичного потока типа IStream. . и возвращает дескриптор этого списка изображений. IStream — это объект OLE, и его объявление в Delphi имеет вид TStreamAdapter = class(TInterfacedObject, IStream), что означает, что TStreamAdapter — это объект, унаследованный от TInterfacedObject, который управляет интерфейсом IStream. С помощью объекта TStreamAdapter можно реализовать манипулирование объектом интерфейса ISTream внутренним объектом TStream Delphi. |
| Способ второй: |
| Наследуйте подкласс TImageListEx от TImageList и реализуйте собственные методы SaveToFileEx и SaveToStreamEx. По умолчанию изображения, сохраненные в TImageList, состоят из обычных изображений и изображений их масок, поэтому необходимо вызвать метод GetImages(Index: Integer; Image, Mask:, предоставленный частью PROtected его базового класса TCustomImageList). TBitmap) для получения растрового изображения с указанным порядковым номером в списке изображений и его растрового изображения маски, а затем сохранения их в пользовательский файл или двоичный поток соответственно. Кроме того, необходимо предоставить методы LoadFromFileEx и LoadFromStreamEx для получения. растровое изображение из пользовательского файла или двоичного потока. Восстановить коллекцию изображений из потока. |
| Этапы реализации |
| Пользовательский элемент управления TImageListEx инкапсулирует два вышеуказанных метода в публичной части. |
| Исходный код класса TImageListEx выглядит следующим образом: |
| модуль ImageListEx; |
| интерфейс |
| использует Windows, SysUtils, классы, графику, элементы управления, Commctrl, ImgList, Consts; |
| тип |
| TImageListEx = класс (TImageList) |
| общественный |
| процедура LoadFromFile(const FileName: string);//Реализовать метод API для сохранения |
| процедура LoadFromStream(Stream: TStream); |
| процедура SaveToFile (const FileName: строка); |
| процедура SaveToStream(Stream: TStream); |
| процедура LoadFromFileEx(const FileName: string);//Достигаем собственного метода сохранения |
| процедура LoadFromStreamEx(Stream: TStream); |
| процедура SaveToFileEx (const FileName: строка); |
| процедура SaveToStreamEx(Stream: TStream); |
| конец; |
| процедура Регистр; |
| выполнение |
| процедура Регистр; |
| начинать |
| RegisterComponents('ImageListEx', [TImageListEx]); |
| конец; |
| {TImageListEx} |
| процедура TImageListEx.LoadFromFile(const FileName: string); |
| вар |
| Поток: ТСтрим; |
| начинать |
| Поток:= TFileStream.Create(FileName, fmOpenRead); |
| пытаться |
| ЗагрузитьИзПотока(Поток); |
| окончательно |
| Стрим.Бесплатно; |
| конец; |
| конец; |
| процедура TImageListEx.LoadFromFileEx(const FileName: string); |
| вар |
| Поток: ТСтрим; |
| начинать |
| Поток:= TFileStream.Create(FileName, fmOpenRead); |
| пытаться |
| LoadFromStreamEx(Поток); |
| окончательно |
| Стрим.Бесплатно; |
| конец; |
| конец; |
| процедура TImageListEx.LoadFromStream(Stream: TStream); |
| вар |
| SA: TStreamAdapter; |
| начинать |
| SA := TStreamAdapter.Create(Stream); |
| пытаться |
| Handle := ImageList_Read(SA); //Указываем дескриптор текущего списка изображений на дескриптор, полученный из двоичного потока |
| если Ручка = 0, то |
| поднять EReadError.CreateRes(@SImageReadFail); |
| окончательно |
| SA.Бесплатно; |
| конец; |
| конец; |
| процедура TImageListEx.LoadFromStreamEx(Stream: TStream); |
| вар |
| Ширина, Высота: Целое число; |
| Растровое изображение, Маска: TBitmap; |
| БинStream: TMemoryStream; |
| процедура LoadImageFromStream (Изображение: TBitmap); |
| вар |
| Подсчет: DWord; |
| начинать |
| Изображение.Назначить(ноль); |
| Stream.ReadBuffer(Count, SizeOf(Count));//Сначала читаем размер растрового изображения |
| БинСтрим.Очистить; |
| BinStream.CopyFrom(Stream, Count);//Затем читаем растровое изображение |
| BinStream.Position := 0; //Сброс указателя потока |
| Изображение.LoadFromStream(BinStream); |
| конец; |
| начинать |
| Stream.ReadBuffer(Height, SizeOf(Height)); |
| Stream.ReadBuffer(Width, SizeOf(Width)); |
| Self.Height := Высота; |
| Self.Width := Width;//Восстанавливаем исходную высоту и ширину списка изображений |
| Растровое изображение := TBitmap.Create; |
| Маска := TBitmap.Create; |
| BinStream := TMemoryStream.Create; |
| пытаться |
| в то время как Stream.Position <> Stream.Size делает |
| начинать |
| LoadImageFromStream(Bitmap);//Читать растровое изображение из двоичного потока |
| LoadImageFromStream(Mask);//Читаем растровое изображение маски из двоичного потока |
| Add(Bitmap, Mask);//Добавляем растровое изображение и его растровую маску в список изображений |
| конец; |
| окончательно |
| Растровое изображение.Бесплатно; |
| Маска.Бесплатно; |
| БинСтрим.Бесплатно; |
| конец; |
| конец; |
| процедура TImageListEx.SaveToFile (const FileName: строка); |
| вар |
| Поток: ТСтрим; |
| начинать |
| Поток:= TFileStream.Create(FileName, fmCreate); |
| пытаться |
| SaveToStream(Поток); |
| окончательно |
| Стрим.Бесплатно; |
| конец; |
| конец; |
| процедура TImageListEx.SaveToFileEx(const FileName: string); |
| вар |
| Поток: ТСтрим; |
| начинать |
| Поток:= TFileStream.Create(FileName, fmCreate); |
| пытаться |
| SaveToStreamEx(Поток); |
| окончательно |
| Стрим.Бесплатно; |
| конец; |
| конец; |
| процедура TImageListEx.SaveToStream(Stream: TStream); |
| вар |
| SA: TStreamAdapter; |
| начинать |
| SA := TStreamAdapter.Create(Stream); |
| пытаться |
| если не ImageList_Write(Handle, SA), то //сохраняем текущий список изображений в двоичный поток |
| поднять EWriteError.CreateRes(@SImageWriteFail); |
| окончательно |
| SA.Бесплатно; |
| конец; |
| конец; |
| процедура TImageListEx.SaveToStreamEx(Stream: TStream); |
| вар |
| Я: целое число; |
| Ширина, Высота: целое число; |
| Растровое изображение, Маска: TBitmap; |
| БинStream: TMemoryStream; |
| процедура SetImage (Изображение: TBitmap; IsMask: Boolean); |
| начинать |
| Image.Assign(nil);//Очистить последнее сохраненное изображение, чтобы избежать перекрытия изображений |
| с изображением сделать |
| начинать |
| if IsMask then MonoChrome := True;//Растровое изображение маски должно быть монохромным |
| Высота := Self.Height; |
| Ширина := Self.Width; |
| конец; |
| конец; |
| процедура SaveImageToStream (Изображение: TBitmap); |
| вар |
| Подсчет: DWORD; |
| начинать |
| БинСтрим.Очистить; |
| Изображение.SaveToStream(BinStream); |
| Количество: = BinStream.Size; |
| Stream.WriteBuffer(Count, SizeOf(Count));//Сначала сохраняем размер растрового изображения |
| Stream.CopyFrom(BinStream, 0);//Затем сохраняем растровое изображение |
| конец; |
| начинать |
| Высота := Self.Height; |
| Ширина := Self.Width; |
| Stream.WriteBuffer(Height, SizeOf(Height));//Сохраняем высоту исходного списка изображений |
| Stream.WriteBuffer(Width, SizeOf(Width));//Сохраняем ширину исходного списка изображений |
| Растровое изображение := TBitmap.Create; |
| Маска := TBitmap.Create; |
| BinStream := TMemoryStream.Create; |
| пытаться |
| for I := 0 to Count - 1 do//Сохраняем изображение в списке изображений |
| начинать |
| SetImage(Растровое изображение, Ложь); |
| SetImage(Маска, Истина); |
| GetImages(I, Bitmap, Mask);//Получаем растровое изображение с указанным номером индекса и его растровую маску |
| SaveImageToStream(Bitmap);//Сохранить растровое изображение в двоичный поток |
| SaveImageToStream(Mask);//Сохраняем растровое изображение маски в двоичный поток |
| конец; |
| окончательно |
| Растровое изображение.Бесплатно; |
| Маска.Бесплатно; |
| БинСтрим.Бесплатно; |
| конец; |
| конец; |
| конец. |
| Ниже показано, как использовать его в Delphi: |
| Сначала создайте новый проект в Delphi, а затем поместите элемент управления ImageListEx, элемент управления TreeView и четыре элемента управления Button на форму Form1. Свяжите свойство Images элемента управления TreeView с ImageListEx, добавьте любое количество изображений в ImageListEx и добавьте соответствующее количество элементов в TreeView. Свойства элементов ImageIndex соответствуют индексным номерам изображений в ImageListEx. Теперь соответствующий значок может отображаться перед каждым элементом в TreeView. |
| Наконец, напишите в событии OnClick кнопки Button1: |
| ImageListEx1.SaveToFile('C:CJ.dat'); |
| ImageListEx1.SaveToFileEx('C:CJEx.dat'); |
| В событии OnClick кнопки Button2 напишите: ImageListEx1.Clear; |
| Напишите в событии OnClick кнопки Button3: ImageListEx1.LoadFromFile('C:CJ.dat'); |
| Напишите в событии OnClick кнопки Button4: ImageListEx1.LoadFromFileEx('C:CJEx.dat'); |
| Запустите программу, сначала нажмите «Кнопка1», затем нажмите «Кнопка2» и, наконец, нажмите «Кнопка3» или «Кнопка4». Вы можете видеть, что программа может сохранять изображения в списке изображений в указанный файл, а также может корректно восстанавливать и отображать их из указанного файла. . |
| Заключение |
| Содержимое, представленное в этой статье, было использовано для решения ситуации, с которой я столкнулся в реальных проектах. Я также надеюсь, что программисты, которые также столкнулись с этой проблемой, смогут найти в ней ответ. Приведенный выше код прошел отладку и запущен в Delphi5.0 и Windows2000 Server. |