최근 프로젝트를 진행하면서 필요할 때 동적으로 복원할 수 있도록 이미지 목록(TImageList)의 일련의 이미지를 지정된 파일이나 바이너리 스트림에 저장해야 하는 상황에 직면했습니다. 그래서 델파이의 도움말에서 TImageList 클래스와 관련된 속성과 메소드를 검색했습니다. 불행하게도 델파이는 TImageList에 SaveToFile 및 SaveToStream 메소드를 제공하지 않았습니다. 따라서 현재 TImageList의 한계를 고려하여 다른 메소드를 채택해야 합니다. 실제 프로젝트 요구 사항을 충족하는 TImageList의 기능입니다. |
해결책 |
방법 1: |
API 함수 ImageList_Write 및 ImageList_Read를 사용하세요. 둘 다 IStream 유형의 매개변수를 지정해야 합니다. 전자의 기능은 지정된 핸들의 이미지 목록을 IStream 유형의 이진 스트림에 저장하는 것입니다. 후자는 IStream 유형의 이진 스트림에서 원래 저장된 이미지 목록을 읽는 것입니다. . , 이 이미지 목록에 대한 핸들을 반환합니다. IStream은 OLE 객체이고 Delphi에서의 선언은 TStreamAdapter = class(TInterfacedObject, IStream)입니다. 이는 TStreamAdapter가 IStream 인터페이스를 조작하는 TInterfacedObject에서 상속된 객체임을 의미합니다. TStreamAdapter 객체를 통해 Delphi 내부 TStream 객체에 의한 IStream 인터페이스 객체 조작이 실현될 수 있습니다. |
방법 2: |
TImageList에서 서브클래스 TImageListEx를 상속하고 사용자 정의 SaveToFileEx 및 SaveToStreamEx 메소드를 구현합니다. 기본적으로 TImageList에 저장된 이미지는 일반 이미지와 마스크 이미지로 구성되어 있으므로 기본 클래스 TCustomImageList의 PRotected 부분에서 제공하는 GetImages(Index: Integer; Image, Mask:를 호출해야 함) TBitmap) 메서드를 사용하면 이미지 목록에서 지정된 인덱스 번호와 마스크 비트맵을 얻은 다음 각각 사용자 정의 파일이나 바이너리 스트림에 저장합니다. 또한 LoadFromFileEx 및 LoadFromStreamEx 메서드를 제공하여 얻을 수 있습니다. 사용자 정의 파일 또는 바이너리 스트림의 비트맵. 스트림에서 이미지 컬렉션을 복원합니다. |
구현 단계 |
사용자 정의 TImageListEx 컨트롤은 위의 두 가지 메소드를 Public 부분에 캡슐화합니다. |
TImageListEx 클래스의 소스 코드는 다음과 같습니다. |
단위 ImageListEx; |
인터페이스 |
Windows, SysUtils, 클래스, 그래픽, 컨트롤, Commctrl, ImgList, Consts를 사용합니다. |
유형 |
TImageListEx = 클래스(TImageList) |
공공의 |
Procedure LoadFromFile(const FileName: string);//저장할 API 메소드 구현 |
절차 LoadFromStream(스트림: TStream); |
프로시저 SaveToFile(const FileName: 문자열); |
절차 SaveToStream(스트림: TStream); |
절차 LoadFromFileEx(const FileName: string);//사용자 정의 저장 방법 달성 |
절차 LoadFromStreamEx(스트림: TStream); |
프로시저 SaveToFileEx(const FileName: 문자열); |
절차 SaveToStreamEx(스트림: TStream); |
끝; |
절차 등록; |
구현 |
절차 등록; |
시작하다 |
RegisterComponents('ImageListEx', [TImageListEx]); |
끝; |
{TImageListEx} |
절차 TImageListEx.LoadFromFile(const FileName: 문자열); |
var |
스트림: TStream; |
시작하다 |
스트림 := TFileStream.Create(FileName, fmOpenRead); |
노력하다 |
LoadFromStream(스트림); |
마지막으로 |
스트림.무료; |
끝; |
끝; |
절차 TImageListEx.LoadFromFileEx(const FileName: 문자열); |
var |
스트림: TStream; |
시작하다 |
스트림 := TFileStream.Create(FileName, fmOpenRead); |
노력하다 |
LoadFromStreamEx(스트림); |
마지막으로 |
스트림.무료; |
끝; |
끝; |
절차 TImageListEx.LoadFromStream(스트림: TStream); |
var |
SA: TStreamAdapter; |
시작하다 |
SA := TStreamAdapter.Create(Stream); |
노력하다 |
Handle := ImageList_Read(SA); //현재 이미지 목록의 핸들을 바이너리 스트림에서 얻은 핸들로 지정합니다. |
핸들 = 0이면 |
EReadError.CreateRes(@SImageReadFail)를 발생시킵니다. |
마지막으로 |
SA. 무료; |
끝; |
끝; |
절차 TImageListEx.LoadFromStreamEx(스트림: TStream); |
var |
너비, 높이: 정수; |
비트맵, 마스크: TBitmap; |
BinStream: TMemoryStream; |
절차 LoadImageFromStream(이미지: TBitmap); |
var |
개수: DWord; |
시작하다 |
이미지.할당(nil); |
Stream.ReadBuffer(Count, SizeOf(Count));//먼저 비트맵의 크기를 읽습니다. |
BinStream.Clear; |
BinStream.CopyFrom(Stream, Count);//그런 다음 비트맵을 읽습니다. |
BinStream.Position := 0; //스트림 포인터 재설정 |
Image.LoadFromStream(BinStream); |
끝; |
시작하다 |
Stream.ReadBuffer(높이, SizeOf(높이)); |
Stream.ReadBuffer(너비, SizeOf(너비)); |
자체.높이 := 높이; |
Self.Width := Width;//이미지 목록의 원래 높이와 너비를 복원합니다. |
비트맵 := TBitmap.Create; |
마스크 := TBitmap.Create; |
BinStream := TMemoryStream.Create; |
노력하다 |
Stream.Position <> Stream.Size 하는 동안 |
시작하다 |
LoadImageFromStream(Bitmap);//바이너리 스트림에서 비트맵 읽기 |
LoadImageFromStream(Mask);//바이너리 스트림에서 마스크 비트맵을 읽습니다. |
Add(Bitmap, Mask);//비트맵과 해당 마스크 비트맵을 이미지 목록에 추가합니다. |
끝; |
마지막으로 |
비트맵.무료; |
마스크.무료; |
BinStream.Free; |
끝; |
끝; |
절차 TImageListEx.SaveToFile(const FileName: 문자열); |
var |
스트림: TStream; |
시작하다 |
스트림 := TFileStream.Create(FileName, fmCreate); |
노력하다 |
SaveToStream(스트림); |
마지막으로 |
스트림.무료; |
끝; |
끝; |
절차 TImageListEx.SaveToFileEx(const FileName: string); |
var |
스트림: TStream; |
시작하다 |
스트림 := TFileStream.Create(FileName, fmCreate); |
노력하다 |
SaveToStreamEx(스트림); |
마지막으로 |
스트림.무료; |
끝; |
끝; |
절차 TImageListEx.SaveToStream(스트림: TStream); |
var |
SA: TStreamAdapter; |
시작하다 |
SA := TStreamAdapter.Create(Stream); |
노력하다 |
ImageList_Write(Handle, SA)가 아닌 경우 //현재 이미지 목록을 바이너리 스트림에 저장합니다. |
EWriteError.CreateRes(@SImageWriteFail)를 발생시킵니다. |
마지막으로 |
SA. 무료; |
끝; |
끝; |
절차 TImageListEx.SaveToStreamEx(스트림: TStream); |
var |
I: 정수; |
너비, 높이: 정수; |
비트맵, 마스크: TBitmap; |
BinStream: TMemoryStream; |
절차 SetImage(이미지: TBitmap; IsMask: 부울); |
시작하다 |
Image.Assign(nil);//이미지 중복을 피하기 위해 마지막으로 저장된 이미지를 지웁니다. |
이미지와 함께 |
시작하다 |
if IsMask then MonoChrome := True;//마스크 비트맵은 단색을 사용해야 합니다. |
높이 := 자체.높이; |
폭 := 자체.폭; |
끝; |
끝; |
절차 SaveImageToStream(이미지: TBitmap); |
var |
개수: DWORD; |
시작하다 |
BinStream.Clear; |
Image.SaveToStream(BinStream); |
개수 := BinStream.Size; |
Stream.WriteBuffer(Count, SizeOf(Count));//먼저 비트맵의 크기를 저장합니다. |
Stream.CopyFrom(BinStream, 0);//그런 다음 비트맵을 저장합니다. |
끝; |
시작하다 |
높이 := 자체.높이; |
폭 := 자체.폭; |
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(비트맵, False); |
SetImage(마스크, 참); |
GetImages(I, Bitmap, Mask);//지정된 인덱스 번호와 해당 마스크 비트맵이 있는 비트맵을 가져옵니다. |
SaveImageToStream(Bitmap);//비트맵을 바이너리 스트림에 저장 |
SaveImageToStream(Mask);//마스크 비트맵을 바이너리 스트림에 저장합니다. |
끝; |
마지막으로 |
비트맵.무료; |
마스크.무료; |
BinStream.Free; |
끝; |
끝; |
끝. |
다음은 Delphi에서 이를 사용하는 방법을 보여줍니다. |
먼저 Delphi에서 새 프로젝트를 만든 다음 ImageListEx 컨트롤, TreeView 컨트롤 및 4개의 Button 컨트롤을 Form1에 배치합니다. TreeView 컨트롤의 Images 속성을 ImageListEx와 연결하고, ImageListEx에 원하는 수의 이미지를 추가하고, 해당 항목 수를 TreeView에 추가합니다. 항목의 ImageIndex 속성은 ImageListEx에 있는 이미지의 인덱스 번호에 해당합니다. 이제 TreeView의 각 항목 앞에 해당 아이콘이 표시될 수 있습니다. |
마지막으로 Button1의 OnClick 이벤트를 작성합니다. |
ImageListEx1.SaveToFile('C:CJ.dat'); |
ImageListEx1.SaveToFileEx('C:CJEx.dat'); |
Button2의 OnClick 이벤트에서 다음을 작성하십시오. ImageListEx1.Clear; |
Button3의 OnClick 이벤트에 다음을 작성합니다. ImageListEx1.LoadFromFile('C:CJ.dat'); |
Button4의 OnClick 이벤트에 다음을 작성합니다. ImageListEx1.LoadFromFileEx('C:CJEx.dat'); |
프로그램을 실행하고 먼저 Button1을 클릭한 다음 Button2를 클릭하고 마지막으로 Button3 또는 Button4를 클릭하면 프로그램이 이미지 목록의 이미지를 지정된 파일에 저장하고 지정된 파일에서 올바르게 복원하고 표시할 수 있음을 알 수 있습니다. . |
결론 |
본 글에서 소개한 내용은 실제 프로젝트에서 제가 겪은 상황을 해결하는데 활용되었으며, 또한 이 문제에 직면한 프로그래머들도 그 해답을 찾을 수 있기를 바랍니다. 위의 코드는 Delphi5.0 및 Windows2000 Server에서 디버깅 및 실행을 통과했습니다. |