Недавно во время работы над проектом я столкнулся с ситуацией сохранения серии изображений в списке изображений (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. |