Writing, reloading component status (images)

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Writing, reloading component status (images)

Postby mark_c » Wed Jan 09, 2019 1:58 am

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);
}
//---------------------------------------------------------------------------
mark_c
BCBJ Guru
BCBJ Guru
 
Posts: 163
Joined: Thu Jun 21, 2012 1:13 am

Re: Writing, reloading component status (images)

Postby rlebeau » Wed Jan 09, 2019 12:34 pm

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.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1603
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Writing, reloading component status (images)

Postby mark_c » Wed Jan 09, 2019 1:40 pm

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);
}
//---------------------------------------------------------------------------
mark_c
BCBJ Guru
BCBJ Guru
 
Posts: 163
Joined: Thu Jun 21, 2012 1:13 am

Re: Writing, reloading component status (images)

Postby rlebeau » Wed Jan 09, 2019 6:31 pm

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.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1603
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Writing, reloading component status (images)

Postby mark_c » Fri Jan 11, 2019 1:23 pm

tnx Remy
mark_c
BCBJ Guru
BCBJ Guru
 
Posts: 163
Joined: Thu Jun 21, 2012 1:13 am

Re: Writing, reloading component status (images)

Postby ericsmith » Fri Jun 21, 2019 9:45 pm

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!
ericsmith
 
Posts: 1
Joined: Fri Jun 21, 2019 9:38 pm


Return to Technical

Who is online

Users browsing this forum: No registered users and 22 guests