Page 1 of 1

Writing, reloading component status (images)

PostPosted: Wed Jan 09, 2019 1:58 am
by mark_c
Hello,
I wrote using code found to network, a small example that collects images on an ImageList component.
I found that the WriteComponentResFile function allows me to save the component status but I did not understand how it should be restored using the ReadComponentResFile function that does not seem to work.

Thank you

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "jpeg.hpp"

int ni=0;

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
        for(int i=0;i<FileListBox1->Items->Count;i++)
        {
                Graphics::TBitmap *bmp = new Graphics::TBitmap;
                TJPEGImage *jpeg = new TJPEGImage;

                jpeg->LoadFromFile(FileListBox1->Items->Strings[i]);
                bmp->Assign(jpeg);

                TListItem *pItem;
                ImageList1->Add(bmp, NULL);
                pItem = ListView1->Items->Add();
                pItem->Caption = GetCurrentDir() + "\\" + FileListBox1->Items->Strings[i];
                pItem->ImageIndex = ni++;

                delete bmp;
                delete jpeg;
        }

        WriteComponentResFile("ImageList.dat", ImageList1);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
        ImageList1->Clear();
        ListView1->Items->Clear();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)
{
        ReadComponentResFile("ImageList.dat", ImageList1);
}
//---------------------------------------------------------------------------

Re: Writing, reloading component status (images)

PostPosted: Wed Jan 09, 2019 12:34 pm
by rlebeau
Works fine for me. What part of it is not working for you exactly?

Here are some alternative approaches to saving/loading a TImageList:

Save/Load TImageList to/from a file ...

I do notice some issues in your code, though:

- you are not clearing the TImageList before re-populating it with ReadComponentResFile().

- you should not be using GetCurrentDir() to get the directory that the TFileListBox is displaying. Use the TFileListBox1::Directory property instead.

- for the TListItem::ImageIndex property, you should be using the index that TImageList::Add() returns, instead of maintaining your own index variable separately.

Re: Writing, reloading component status (images)

PostPosted: Wed Jan 09, 2019 1:40 pm
by mark_c
thanks as always Remy,
but I can merge the two files "ImageList.dat" and "ListView.dat" to one?

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "jpeg.hpp"


//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
        TListItem *pItem;

        for(int i=0;i<FileListBox1->Items->Count;i++)
        {
                Graphics::TBitmap *bmp = new Graphics::TBitmap;
                TJPEGImage *jpeg = new TJPEGImage;

                jpeg->LoadFromFile(FileListBox1->Items->Strings[i]);
                bmp->Assign(jpeg);

                ImageList1->Add(bmp, NULL);

                pItem = ListView1->Items->Add();
                pItem->Caption = FileListBox1->Directory + "\\" + FileListBox1->Items->Strings[i];
                pItem->ImageIndex = i;

                delete bmp;
                delete jpeg;
        }

        WriteComponentResFile("ImageList.dat", ImageList1);
        WriteComponentResFile("ListView.dat", ListView1);

        Label1->Caption=ImageList1->Count;

}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
        ImageList1->Clear();
        ListView1->Items->Clear();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)
{
        ImageList1->Clear();
        ListView1->Items->Clear();

        ReadComponentResFile("ImageList.dat", ImageList1);
        ReadComponentResFile("ListView.dat", ListView1);
}
//---------------------------------------------------------------------------

Re: Writing, reloading component status (images)

PostPosted: Wed Jan 09, 2019 6:31 pm
by rlebeau
mark_c wrote:I can merge the two files "ImageList.dat" and "ListView.dat" to one?


Not with WriteComponentResFile(), no. You would need to implement your own custom file format to store what you need. For example:

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "jpeg.hpp"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall WriteComponentResStream(TStream *Stream, TComponent *Instance)
{
    TStream *MStream = new TMemoryStream;
    try
    {
        MStream->WriteComponentRes(Instance->ClassName(), Instance);
        __int64 Size = MStream->Size;
        Stream->WriteBuffer(&Size, sizeof(Size));
        Stream->CopyFrom(MStream, 0);
    }
    __finally
    {
        delete MStream;
    }
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    for(int i = 0; i < FileListBox1->Items->Count; ++i)
    {
        String FileName = IncludeTrailingPathDelimiter(FileListBox1->Directory) + FileListBox1->Items->Strings[i];
        int ImageIndex;

        Graphics::TBitmap *bmp = new Graphics::TBitmap;
        try
        {
            TJPEGImage *jpeg = new TJPEGImage;
            try
            {
                jpeg->LoadFromFile(FileName);
                bmp->Assign(jpeg);
            }
            __finally
            {
                delete jpeg;
            }
            ImageIndex = ImageList1->Add(bmp, NULL);
        }
        __finally
        {
            delete bmp;
        }

        TListItem *pItem = ListView1->Items->Add();
        pItem->Caption = FileName;
        pItem->ImageIndex = ImageIndex;
    }

    Label1->Caption = ImageList1->Count;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmCreate);
    try
    {
        WriteComponentResStream(FStream, ImageList1);
        WriteComponentResStream(FStream, ListView1);
    }
    __finally
    {
        delete FStream;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;
}
//---------------------------------------------------------------------------
TComponent* __fastcall ReadComponentResStream(TStream *Stream, TComponent *Instance)
{
    TComponent *Result;
    TStream *MStream = new TMemoryStream;
    try
    {
        __int64 Size = 0;
        Stream->ReadBuffer(&Size, sizeof(Size));
        if (Size != 0) MStream->CopyFrom(Stream, Size);
        Result = MStream->ReadComponentRes(Instance);
    }
    __finally
    {
        delete MStream;
    }
    return Result;
}

void __fastcall TForm1::Button3Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmOpenRead | fmShareDenyWrite);
    try
    {
        ReadComponentResStream(FStream, ImageList1);
        ReadComponentResStream(FStream, ListView1);
    }
    __finally
    {
        delete FStream;
    }

    Label1->Caption = ImageList1->Count;
}
//---------------------------------------------------------------------------


That being said, I think DFM resources are self-delimiting, so it MIGHT be possible to do away with the TMemoryStream handling, but I'm not sure as I haven't tried it yet:

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "jpeg.hpp"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    for(int i = 0; i < FileListBox1->Items->Count; ++i)
    {
        String FileName = IncludeTrailingPathDelimiter(FileListBox1->Directory) + FileListBox1->Items->Strings[i];
        int ImageIndex;

        Graphics::TBitmap *bmp = new Graphics::TBitmap;
        try
        {
            TJPEGImage *jpeg = new TJPEGImage;
            try
            {
                jpeg->LoadFromFile(FileName);
                bmp->Assign(jpeg);
            }
            __finally
            {
                delete jpeg;
            }
            ImageIndex = ImageList1->Add(bmp, NULL);
        }
        __finally
        {
            delete bmp;
        }

        TListItem *pItem = ListView1->Items->Add();
        pItem->Caption = FileName;
        pItem->ImageIndex = ImageIndex;
    }

    Label1->Caption = ImageList1->Count;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmCreate);
    try
    {
        FStream->WriteComponentRes(ImageList1->ClassName(), ImageList1);
        FStream->WriteComponentRes(ListView1->ClassName(), ListView1);
    }
    __finally
    {
        delete FStream;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmOpenRead | fmShareDenyWrite);
    try
    {
        FStream->ReadComponentRes(ImageList1);
        FStream->ReadComponentRes(ListView1);
    }
    __finally
    {
        delete FStream;
    }

    Label1->Caption = ImageList1->Count;
}
//---------------------------------------------------------------------------


Using the intermediate TMemoryStream objects allows the file to be explicit about which portions of its data belong to which DFM.

Re: Writing, reloading component status (images)

PostPosted: Fri Jan 11, 2019 1:23 pm
by mark_c
tnx Remy

Re: Writing, reloading component status (images)

PostPosted: Fri Jun 21, 2019 9:45 pm
by ericsmith
rlebeau wrote:
mark_c wrote:I can merge the two files "ImageList.dat" and "ListView.dat" to one?


Not with WriteComponentResFile(), no. You would need to implement your own custom file format to store what you need. For example:

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "jpeg.hpp"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall WriteComponentResStream(TStream *Stream, TComponent *Instance)
{
    TStream *MStream = new TMemoryStream;
    try
    {
        MStream->WriteComponentRes(Instance->ClassName(), Instance);
        __int64 Size = MStream->Size;
        Stream->WriteBuffer(&Size, sizeof(Size));
        Stream->CopyFrom(MStream, 0);
    }
    __finally
    {
        delete MStream;
    }
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    for(int i = 0; i < FileListBox1->Items->Count; ++i)
    {
        String FileName = IncludeTrailingPathDelimiter(FileListBox1->Directory) + FileListBox1->Items->Strings[i];
        int ImageIndex;

        Graphics::TBitmap *bmp = new Graphics::TBitmap;
        try
        {
            TJPEGImage *jpeg = new TJPEGImage;
            try
            {
                jpeg->LoadFromFile(FileName);
                bmp->Assign(jpeg);
            }
            __finally
            {
                delete jpeg;
            }
            ImageIndex = ImageList1->Add(bmp, NULL);
        }
        __finally
        {
            delete bmp;
        }

        TListItem *pItem = ListView1->Items->Add();
        pItem->Caption = FileName;
        pItem->ImageIndex = ImageIndex;
    }

    Label1->Caption = ImageList1->Count;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmCreate);
    try
    {
        WriteComponentResStream(FStream, ImageList1);
        WriteComponentResStream(FStream, ListView1);
    }
    __finally
    {
        delete FStream;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;
}
//---------------------------------------------------------------------------
TComponent* __fastcall ReadComponentResStream(TStream *Stream, TComponent *Instance)
{
    TComponent *Result;
    TStream *MStream = new TMemoryStream;
    try
    {
        __int64 Size = 0;
        Stream->ReadBuffer(&Size, sizeof(Size));
        if (Size != 0) MStream->CopyFrom(Stream, Size);
        Result = MStream->ReadComponentRes(Instance);
    }
    __finally
    {
        delete MStream;
    }
    return Result;
}

void __fastcall TForm1::Button3Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmOpenRead | fmShareDenyWrite);
    try
    {
        ReadComponentResStream(FStream, ImageList1);
        ReadComponentResStream(FStream, ListView1);
    }
    __finally
    {
        delete FStream;
    }

    Label1->Caption = ImageList1->Count;
}
//---------------------------------------------------------------------------


That being said, I think DFM resources are self-delimiting, google street view so it MIGHT be possible to do away with the TMemoryStream handling, but I'm not sure as I haven't tried it yet:

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "jpeg.hpp"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    for(int i = 0; i < FileListBox1->Items->Count; ++i)
    {
        String FileName = IncludeTrailingPathDelimiter(FileListBox1->Directory) + FileListBox1->Items->Strings[i];
        int ImageIndex;

        Graphics::TBitmap *bmp = new Graphics::TBitmap;
        try
        {
            TJPEGImage *jpeg = new TJPEGImage;
            try
            {
                jpeg->LoadFromFile(FileName);
                bmp->Assign(jpeg);
            }
            __finally
            {
                delete jpeg;
            }
            ImageIndex = ImageList1->Add(bmp, NULL);
        }
        __finally
        {
            delete bmp;
        }

        TListItem *pItem = ListView1->Items->Add();
        pItem->Caption = FileName;
        pItem->ImageIndex = ImageIndex;
    }

    Label1->Caption = ImageList1->Count;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmCreate);
    try
    {
        FStream->WriteComponentRes(ImageList1->ClassName(), ImageList1);
        FStream->WriteComponentRes(ListView1->ClassName(), ListView1);
    }
    __finally
    {
        delete FStream;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
    ListView1->Items->Clear();
    ImageList1->Clear();
    Label1->Caption = 0;

    TFileStream *FStream = new TFileStream("ImageListAndListView.dat", fmOpenRead | fmShareDenyWrite);
    try
    {
        FStream->ReadComponentRes(ImageList1);
        FStream->ReadComponentRes(ListView1);
    }
    __finally
    {
        delete FStream;
    }

    Label1->Caption = ImageList1->Count;
}
//---------------------------------------------------------------------------


Using the intermediate TMemoryStream objects allows the file to be explicit about which portions of its data belong to which DFM.


thanks do much for the information!