Recientemente, mientras trabajaba en un proyecto, me encontré con la situación de guardar una serie de imágenes en una lista de imágenes (TImageList) en un archivo específico o secuencia binaria para que puedan restaurarse dinámicamente cuando sea necesario. Así que busqué las propiedades y métodos relacionados con la clase TImageList en la ayuda de Delphi. Desafortunadamente, Delphi no proporcionó los métodos SaveToFile y SaveToStream en TImageList. Por lo tanto, en vista de las limitaciones actuales de TImageList, se deben adoptar otros métodos para extender la clase. Funciones de TImageList para satisfacer las necesidades reales del proyecto. |
Solución |
Método uno: |
Utilice las funciones API ImageList_Write e ImageList_Read. Ambos necesitan especificar un parámetro de tipo IStream. La función del primero es guardar la lista de imágenes del identificador especificado en una secuencia binaria de tipo IStream; la segunda es leer la lista de imágenes guardadas originalmente de la secuencia binaria de tipo IStream; , y devuelve un identificador a esta lista de imágenes. IStream es un objeto OLE y su declaración en Delphi es TStreamAdapter = class (TInterfacedObject, IStream), lo que significa que TStreamAdapter es un objeto heredado de TInterfacedObject que manipula la interfaz IStream. A través del objeto TStreamAdapter, se puede realizar la manipulación del objeto de interfaz IStream por el objeto TStream interno de Delphi. |
Método dos: |
Herede una subclase TImageListEx de TImageList e implemente métodos personalizados SaveToFileEx y SaveToStreamEx. De forma predeterminada, las imágenes guardadas en TImageList se componen de imágenes ordinarias y sus imágenes de máscara, por lo que se debe llamar a GetImages (Índice: entero; Imagen, Máscara: proporcionada por la parte PRotected de su clase base TCustomImageList). TBitmap) para obtener el mapa de bits con el número de índice especificado en la lista de imágenes y su mapa de bits de máscara, y luego guardarlos en un archivo personalizado o flujo binario respectivamente. Además, es necesario proporcionar los métodos LoadFromFileEx y LoadFromStreamEx para obtener el. Mapa de bits del archivo personalizado o secuencia binaria. Restaura la colección de imágenes de la secuencia. |
Pasos de implementación |
El control TImageListEx personalizado encapsula los dos métodos anteriores en la parte Pública. |
El código fuente de la clase TImageListEx es el siguiente: |
unidad ImageListEx; |
interfaz |
utiliza Windows, SysUtils, Clases, Gráficos, Controles, Commctrl, ImgList, Consts; |
tipo |
TImageListEx = clase(TImageList) |
público |
procedimiento LoadFromFile(const FileName: string);//Implementar el método API para guardar |
procedimiento LoadFromStream(Stream: TStream); |
procedimiento SaveToFile(const FileName: cadena); |
procedimiento SaveToStream(Stream: TStream); |
procedimiento LoadFromFileEx(const FileName: string);//Lograr un método de guardado personalizado |
procedimiento LoadFromStreamEx(Stream: TStream); |
procedimiento SaveToFileEx(const FileName: cadena); |
procedimiento SaveToStreamEx(Stream: TStream); |
fin; |
Registro de trámites; |
implementación |
Registro de trámites; |
comenzar |
RegisterComponents('ImageListEx', [TImageListEx]); |
fin; |
{TImageListEx} |
procedimiento TImageListEx.LoadFromFile (const FileName: cadena); |
var |
Corriente: TStream; |
comenzar |
Corriente := TFileStream.Create(FileName, fmOpenRead); |
intentar |
LoadFromStream(Corriente); |
finalmente |
Transmitir.Gratis; |
fin; |
fin; |
procedimiento TImageListEx.LoadFromFileEx (const FileName: cadena); |
var |
Corriente: TStream; |
comenzar |
Corriente := TFileStream.Create(FileName, fmOpenRead); |
intentar |
LoadFromStreamEx(corriente); |
finalmente |
Transmitir.Gratis; |
fin; |
fin; |
procedimiento TImageListEx.LoadFromStream(Stream: TStream); |
var |
SA: TStreamAdapter; |
comenzar |
SA := TStreamAdapter.Create(Secuencia); |
intentar |
Handle := ImageList_Read(SA); //Apunta el identificador de la lista de imágenes actual al identificador obtenido de la secuencia binaria |
si Mango = 0 entonces |
elevar EReadError.CreateRes(@SImageReadFail); |
finalmente |
SA.Gratis; |
fin; |
fin; |
procedimiento TImageListEx.LoadFromStreamEx(Stream: TStream); |
var |
Ancho, Alto: Entero; |
Mapa de bits, máscara: TBitmap; |
BinStream: TMemoryStream; |
procedimiento LoadImageFromStream(Imagen: TBitmap); |
var |
Contar: DWord; |
comenzar |
Imagen.Asignar(nulo); |
Stream.ReadBuffer(Count, SizeOf(Count));// Primero lea el tamaño del mapa de bits |
BinStream.Claro; |
BinStream.CopyFrom(Stream, Count);// Luego lee el mapa de bits |
BinStream.Position := 0; //Restablecimiento del puntero de flujo |
Imagen.LoadFromStream(BinStream); |
fin; |
comenzar |
Stream.ReadBuffer(Altura, TamañoDe(Altura)); |
Stream.ReadBuffer(Ancho, TamañoDe(Ancho)); |
Altura propia: = Altura; |
Self.Width := Ancho;//Restaurar la altura y el ancho originales de la lista de imágenes |
Mapa de bits := TBitmap.Create; |
Máscara := TBitmap.Create; |
BinStream := TMemoryStream.Create; |
intentar |
mientras que Stream.Position <> Stream.Size lo hace |
comenzar |
LoadImageFromStream(Bitmap);//Leer mapa de bits de una secuencia binaria |
LoadImageFromStream(Mask);//Leer el mapa de bits de la máscara del flujo binario |
Add(Bitmap, Mask);//Agrega el mapa de bits y su máscara de mapa de bits a la lista de imágenes |
fin; |
finalmente |
Mapa de bits.Gratis; |
Máscara.Gratis; |
BinStream.Gratis; |
fin; |
fin; |
procedimiento TImageListEx.SaveToFile(const FileName: cadena); |
var |
Corriente: TStream; |
comenzar |
Corriente: = TFileStream.Create (Nombre de archivo, fmCreate); |
intentar |
SaveToStream(Corriente); |
finalmente |
Transmitir.Gratis; |
fin; |
fin; |
procedimiento TImageListEx.SaveToFileEx(const FileName: cadena); |
var |
Corriente: TStream; |
comenzar |
Corriente: = TFileStream.Create (Nombre de archivo, fmCreate); |
intentar |
SaveToStreamEx(Transmisión); |
finalmente |
Transmitir.Gratis; |
fin; |
fin; |
procedimiento TImageListEx.SaveToStream(Stream: TStream); |
var |
SA: TStreamAdapter; |
comenzar |
SA := TStreamAdapter.Create(Secuencia); |
intentar |
si no es ImageList_Write(Handle, SA) entonces//Guardar la lista de imágenes actual en la secuencia binaria |
elevar EWriteError.CreateRes(@SImageWriteFail); |
finalmente |
SA.Gratis; |
fin; |
fin; |
procedimiento TImageListEx.SaveToStreamEx(Stream: TStream); |
var |
I: Entero; |
Ancho, Alto: Entero; |
Mapa de bits, máscara: TBitmap; |
BinStream: TMemoryStream; |
procedimiento SetImage(Imagen: TBitmap; IsMask: Booleano); |
comenzar |
Image.Assign(nil);//Borrar la última imagen guardada para evitar la superposición de imágenes |
con imagen hacer |
comenzar |
si IsMask entonces MonoChrome := True;//El mapa de bits de la máscara debe usar monocromo |
Altura: = Altura propia; |
Ancho: = Ancho propio; |
fin; |
fin; |
procedimiento SaveImageToStream(Imagen: TBitmap); |
var |
Contar: DWORD; |
comenzar |
BinStream.Claro; |
Imagen.SaveToStream(BinStream); |
Contar := BinStream.Size; |
Stream.WriteBuffer(Count, SizeOf(Count));//Primero guarde el tamaño del mapa de bits |
Stream.CopyFrom(BinStream, 0);//Luego guarda el mapa de bits |
fin; |
comenzar |
Altura: = Altura propia; |
Ancho: = Ancho propio; |
Stream.WriteBuffer(Height, SizeOf(Height));//Guardar la altura de la lista de imágenes original |
Stream.WriteBuffer(Width, SizeOf(Width));//Guardar el ancho de la lista de imágenes original |
Mapa de bits := TBitmap.Create; |
Máscara := TBitmap.Create; |
BinStream := TMemoryStream.Create; |
intentar |
para I: = 0 para contar - 1 hacer // Guardar la imagen en la lista de imágenes |
comenzar |
SetImage(Mapa de bits, Falso); |
SetImage(Máscara, Verdadero); |
GetImages(I, Bitmap, Mask);//Obtiene el mapa de bits con el número de índice especificado y su mapa de bits de máscara |
SaveImageToStream(Bitmap);//Guardar mapa de bits en secuencia binaria |
SaveImageToStream(Mask);//Guardar el mapa de bits de la máscara en la secuencia binaria |
fin; |
finalmente |
Mapa de bits.Gratis; |
Máscara.Gratis; |
BinStream.Gratis; |
fin; |
fin; |
fin. |
A continuación se muestra cómo usarlo en Delphi: |
Primero cree un nuevo proyecto en Delphi y luego coloque un control ImageListEx, un control TreeView y cuatro controles Button en Form1. Asocie la propiedad Imágenes del control TreeView con ImageListEx, agregue cualquier cantidad de imágenes a ImageListEx y agregue una cantidad correspondiente de elementos a TreeView. Las propiedades ImageIndex de los elementos corresponden a los números de índice de las imágenes en ImageListEx. Ahora se puede mostrar el icono correspondiente antes de cada elemento en TreeView. |
Finalmente, escribe en el evento OnClick del Botón1: |
ImageListEx1.SaveToFile('C:CJ.dat'); |
ImageListEx1.SaveToFileEx('C:CJEx.dat'); |
En el evento OnClick de Button2 escriba: ImageListEx1.Clear; |
Escriba en el evento OnClick de Button3: ImageListEx1.LoadFromFile('C:CJ.dat'); |
Escriba en el evento OnClick de Button4: ImageListEx1.LoadFromFileEx('C:CJEx.dat'); |
Ejecute el programa, primero haga clic en el Botón1, luego haga clic en el Botón2 y finalmente haga clic en el Botón3 o el Botón4. Puede ver que el programa puede guardar las imágenes en la lista de imágenes en el archivo especificado y puede restaurarlas y mostrarlas correctamente desde el archivo especificado. . |
Conclusión |
El contenido presentado en este artículo se ha utilizado para resolver la situación que encontré en proyectos reales. También espero que los programadores que también encuentren este problema puedan encontrar la respuesta. El código anterior pasó la depuración y la ejecución en Delphi5.0 y Windows2000 Server. |