Recentemente, enquanto trabalhava em um projeto, encontrei a situação de salvar uma série de imagens em uma lista de imagens (TImageList) em um arquivo ou fluxo binário especificado para que pudessem ser restauradas dinamicamente quando necessário. Então procurei as propriedades e métodos relacionados à classe TImageList na ajuda do Delphi. Infelizmente, o Delphi não forneceu os métodos SaveToFile e SaveToStream no TImageList. Portanto, tendo em vista as limitações atuais do TImageList, outros métodos devem ser adotados para estender o. funções do TImageList para atender às necessidades reais do projeto. |
Solução |
Método um: |
Use as funções de API ImageList_Write e ImageList_Read. Ambos precisam especificar um parâmetro do tipo IStream. A função do primeiro é salvar a lista de imagens do identificador especificado em um fluxo binário do tipo IStream; . e retorna um identificador para esta lista de imagens. IStream é um objeto OLE e sua declaração em Delphi é TStreamAdapter = class(TInterfacedObject, IStream), o que significa que TStreamAdapter é um objeto herdado de TInterfacedObject que manipula a interface IStream. Através do objeto TStreamAdapter, a manipulação do objeto de interface ISTream pelo objeto TStream interno do Delphi pode ser realizada. |
Método dois: |
Herde uma subclasse TImageListEx de TImageList e implemente os métodos SaveToFileEx e SaveToStreamEx personalizados. Por padrão, as imagens salvas em TImageList são compostas por imagens comuns e suas imagens de máscara, portanto o método GetImages(Index: Integer; Image, Mask: fornecido pela parte PRotected de sua classe base TCustomImageList deve ser chamado) TBitmap) para obter o bitmap com o número de índice especificado na lista de imagens e seu bitmap de máscara e, em seguida, salvá-los em um arquivo personalizado ou fluxo binário, respectivamente. Além disso, é necessário fornecer os métodos LoadFromFileEx e LoadFromStreamEx para obter o. bitmap do arquivo personalizado ou fluxo binário. Restaure a coleção de imagens do fluxo. |
Etapas de implementação |
O controle TImageListEx customizado encapsula os dois métodos acima na parte Pública. |
O código fonte da classe TImageListEx é o seguinte: |
unidade ImageListEx; |
interface |
usa Windows, SysUtils, Classes, Gráficos, Controles, Commctrl, ImgList, Consts; |
tipo |
TImageListEx = classe(TImageList) |
público |
procedimento LoadFromFile(const FileName: string); //Implementa método API para salvar |
procedimento LoadFromStream(Stream: TStream); |
procedimento SaveToFile(const NomeArquivo: string); |
procedimento SaveToStream(Stream: TStream); |
procedimento LoadFromFileEx(const FileName: string); //Obter método de salvamento personalizado |
procedimento LoadFromStreamEx(Stream: TStream); |
procedimento SaveToFileEx(const NomeArquivo: string); |
procedimento SaveToStreamEx(Stream: TStream); |
fim; |
Cadastro de procedimento; |
implementação |
Cadastro de procedimento; |
começar |
RegisterComponents('ImageListEx', [TImageListEx]); |
fim; |
{TImageListEx} |
procedimento TImageListEx.LoadFromFile(const NomeArquivo: string); |
var |
Fluxo: TStream; |
começar |
Fluxo := TFileStream.Create(FileName, fmOpenRead); |
tentar |
LoadFromStream(Stream); |
finalmente |
Stream.Grátis; |
fim; |
fim; |
procedimento TImageListEx.LoadFromFileEx(const FileName: string); |
var |
Fluxo: TStream; |
começar |
Fluxo := TFileStream.Create(FileName, fmOpenRead); |
tentar |
LoadFromStreamEx(Stream); |
finalmente |
Stream.Grátis; |
fim; |
fim; |
procedimento TImageListEx.LoadFromStream(Stream: TStream); |
var |
SA: TStreamAdapter; |
começar |
SA := TStreamAdapter.Create(Stream); |
tentar |
Handle := ImageList_Read(SA); //Aponta o identificador da lista de imagens atual para o identificador obtido do fluxo binário |
se identificador = 0 então |
raise EReadError.CreateRes(@SImageReadFail); |
finalmente |
SA.Grátis; |
fim; |
fim; |
procedimento TImageListEx.LoadFromStreamEx(Stream: TStream); |
var |
Largura, Altura: Inteiro; |
Bitmap, Máscara: TBitmap; |
BinStream: TMemoryStream; |
procedimento LoadImageFromStream(Imagem: TBitmap); |
var |
Contagem: DWord; |
começar |
Imagem.Assign(nil); |
Stream.ReadBuffer(Count, SizeOf(Count));//Primeiro leia o tamanho do bitmap |
BinStream.Clear; |
BinStream.CopyFrom(Stream, Count);//Em seguida, leia o bitmap |
BinStream.Position := 0; //Redefinição do ponteiro do fluxo |
Image.LoadFromStream(BinStream); |
fim; |
começar |
Stream.ReadBuffer(Altura, SizeOf(Altura)); |
Stream.ReadBuffer(Largura, SizeOf(Largura)); |
Auto.Altura := Altura; |
Self.Width := Width;//Restaura a altura e largura originais da lista de imagens |
Bitmap := TBitmap.Create; |
Máscara := TBitmap.Create; |
BinStream := TMemoryStream.Create; |
tentar |
enquanto Stream.Position <> Stream.Size faz |
começar |
LoadImageFromStream(Bitmap); //Lê o bitmap do fluxo binário |
LoadImageFromStream(Mask); //Lê o bitmap da máscara do fluxo binário |
Add(Bitmap, Mask); //Adiciona o bitmap e seu bitmap de máscara à lista de imagens |
fim; |
finalmente |
Bitmap.Grátis; |
Máscara.Grátis; |
BinStream.Free; |
fim; |
fim; |
procedimento TImageListEx.SaveToFile(const FileName: string); |
var |
Fluxo: TStream; |
começar |
Fluxo := TFileStream.Create(FileName, fmCreate); |
tentar |
SaveToStream(Stream); |
finalmente |
Stream.Grátis; |
fim; |
fim; |
procedimento TImageListEx.SaveToFileEx(const FileName: string); |
var |
Fluxo: TStream; |
começar |
Fluxo := TFileStream.Create(FileName, fmCreate); |
tentar |
SaveToStreamEx(Stream); |
finalmente |
Stream.Grátis; |
fim; |
fim; |
procedimento TImageListEx.SaveToStream(Stream: TStream); |
var |
SA: TStreamAdapter; |
começar |
SA := TStreamAdapter.Create(Stream); |
tentar |
se não for ImageList_Write(Handle, SA) então //Salve a lista de imagens atual no fluxo binário |
aumentar EWriteError.CreateRes(@SImageWriteFail); |
finalmente |
SA.Grátis; |
fim; |
fim; |
procedimento TImageListEx.SaveToStreamEx(Stream: TStream); |
var |
Eu: Inteiro; |
Largura, Altura: Inteiro; |
Bitmap, Máscara: TBitmap; |
BinStream: TMemoryStream; |
procedimento SetImage(Imagem: TBitmap; IsMask: Boolean); |
começar |
Image.Assign(nil);//Limpa a última imagem salva para evitar sobreposição de imagens |
com imagem fazer |
começar |
if IsMask then MonoChrome := True;//O bitmap da máscara deve usar monocromático |
Altura := Auto.Altura; |
Largura := Self.Largura; |
fim; |
fim; |
procedimento SaveImageToStream(Imagem: TBitmap); |
var |
Contagem: DWORD; |
começar |
BinStream.Clear; |
Image.SaveToStream(BinStream); |
Contagem := BinStream.Size; |
Stream.WriteBuffer(Count, SizeOf(Count));//Primeiro salve o tamanho do bitmap |
Stream.CopyFrom(BinStream, 0);//Em seguida, salve o bitmap |
fim; |
começar |
Altura := Auto.Altura; |
Largura := Self.Largura; |
Stream.WriteBuffer(Height, SizeOf(Height));//Salva a altura da lista de imagens original |
Stream.WriteBuffer(Width, SizeOf(Width));//Salva a largura da lista de imagens original |
Bitmap := TBitmap.Create; |
Máscara := TBitmap.Create; |
BinStream := TMemoryStream.Create; |
tentar |
for I := 0 to Count - 1 do//Salve a imagem na lista de imagens |
começar |
SetImage(Bitmap, Falso); |
SetImage(Máscara, Verdadeiro); |
GetImages(I, Bitmap, Mask); //Obtém o bitmap com o número de índice especificado e seu bitmap de máscara |
SaveImageToStream(Bitmap); //Salva bitmap no fluxo binário |
SaveImageToStream(Mask); //Salva o bitmap da máscara no fluxo binário |
fim; |
finalmente |
Bitmap.Grátis; |
Máscara.Grátis; |
BinStream.Free; |
fim; |
fim; |
fim. |
A seguir demonstramos como usá-lo no Delphi: |
Primeiro crie um novo projeto em Delphi e, em seguida, coloque um controle ImageListEx, um controle TreeView e quatro controles Button no Form1. Associe a propriedade Images do controle TreeView a ImageListEx, adicione qualquer número de imagens a ImageListEx e adicione um número correspondente de itens a TreeView. As propriedades ImageIndex dos itens correspondem aos números de índice das imagens em ImageListEx. Agora o ícone correspondente pode ser exibido antes de cada item no TreeView. |
Por fim, escreva no evento OnClick do Button1: |
ImageListEx1.SaveToFile('C:CJ.dat'); |
ImageListEx1.SaveToFileEx('C:CJEx.dat'); |
No evento OnClick do Button2 escreva: ImageListEx1.Clear; |
Escreva no evento OnClick do Button3: ImageListEx1.LoadFromFile('C:CJ.dat'); |
Escreva no evento OnClick do Button4: ImageListEx1.LoadFromFileEx('C:CJEx.dat'); |
Execute o programa, primeiro clique em Button1, depois clique em Button2 e, finalmente, clique em Button3 ou Button4. Você pode ver que o programa pode salvar as imagens na lista de imagens no arquivo especificado e pode restaurá-las e exibi-las corretamente a partir do arquivo especificado. . |
Conclusão |
O conteúdo apresentado neste artigo foi usado para resolver a situação que encontrei em projetos reais. Também espero que os programadores que também enfrentam esse problema possam encontrar a resposta nele. O código acima passou na depuração e execução no Delphi5.0 e no Windows2000 Server. |