オブジェクトの保存/復帰を実現するには?

解決


けん  2004-12-05 10:08:44  No: 12123

こんばんは、いつもお世話になりますケンです。
今回はDelphiでのオブジェクトの保存について質問させていただきます。

基本的には、オブジェクトの保存/復帰を行いたいのですが、復帰後の参照の解決の方法が分からないのです。

以下に具体的な例を挙げて説明します。
type
  TData = class(TComponent)
    private
      FSubData:TSubData;
    protected
//  OwnerとしてSelfを返すメソッド↓
      function GetChildOwner():TComponent;override;
// 自身が現在保持している子コンポーネントを返すメソッド↓ 
      procedure GetChildren(Proc: TGetChildProc;Root: TComponent);override;

    published
//  保存対象へのインタフェースを定義
      property SubData:TSubData read FSubData  write FSubData;
  end;

  TSubData = class(TComponent)    // TSubDataはOWnerとしてTDataを持つ
     private
       FName:String;
       FID:Integer;

     published
//  保存対象の実体を定義
       property Name:String read FName;
       property ID:Integer  read FID;
  end;

のような形で定義されたクラスがあった場合、TDataというオブジェクトの
まとまりでファイルに保存/復帰を実現するために以下のようなコードを利用
しました
// ストリームへクラスの登録
initialization
  RegisterClasses([TData,TSubData]);

// オブジェクトの保存
procedure TMain.SaveObject(FileName:String);
var
  Memory:TMemoryStream;
  FileStream:TFileStream;
begin
  FileStream := TFileStream.Create(FileName,fmCreate);
  Memory := TMemoryStream.Create;
  try
    if FData <> nil then  // FDataはTDataのインスタンスです。
    begin
      Memory.WriteComponent(FData);
      Memory.Seek(0, soFromBeginning);
      ObjectBinaryToText(Memory,FileStream);
    end;
  finally
    FileStream.Free;
    Memory.Free;
  end;
end;

// オブジェクトの復帰
procedure TMain.LoadObject(FileName:String);
var
  Memory:TMemoryStream;
  FileStream:TFileStream;
begin
  FileStream := TFileStream.Create(FileName,fmOpenRead);
  Memory := TMemoryStream.Create;
  try
    ObjectTextToBinary(FileStream,Memory);
    Memory.Seek(0,soFromBeginning);

 // FDataはTDataのインスタンスです
    FData := TData(Memory.ReadComponent(nil));
  finally
    Memory.Free;
    FileStream.Free;
  end;
end;

実行結果を見てみると、オブジェクトの保存は正常に行われているようなのですが、オブジェクトの
復帰の方がうまく処理されていないようです。
特に、TDataのなかのプロパティSubDataのように通常は「参照」として保持されている値の解決が正常に行われていないようです。

このような部分については何か特別なコードの記述が必要なのでしょうか?
アドバイス、お願いいたします。


Mr.XRAY  URL  2004-12-05 11:20:50  No: 12124

ちょっと拝見しただけなので,もしかしたら外している可能性が大ですが,
FSubData:TSubData;
というのは,クラス(オブジェクト)型ですので,SetXXXXというメソッド
で書込む必要があるのかも知れません.
これは通常のコンポーネントと同じ扱いです.


Mr.XRAY  URL  2004-12-05 11:28:48  No: 12125

それからちょっと気になったのですが,

ObjectTextToBinary(FileStream,Memory);

を実行していますが,これ必要でしょうか.
私は使用していません.直接StreamのReadComponent(..)
でやっています.


Mr.XRAY  URL  2004-12-05 11:31:10  No: 12126

>を実行していますが,これ必要でしょうか.

あっ,分かりました.ゴメンなさい.
Binaryにして保存しているということですね.


けん  2004-12-17 23:02:14  No: 12127

Mr.XRAYさん、お返事ありがとうございます。
(こちらのレスが遅くなってすいません)
上の問題は一応解決の方向に進みました。
Nameプロパティの設定をしていなかったのが原因みたいです。(^^;A)

しかし、また新たな問題が浮上してきました。
Streamからロードする時Delphiは型情報からオブジェクトを再構築してくれるのですが、

constructor TData.Create(AOwner:TComponent);
begin
  FSubData := TSubData.Create(Self);
  FSubData.Name := 'SubData';
end;

のようにコンストラクタ(このコンストラクタはReadComponent(nil)を実行した時、型情報からオブジェクトを復帰させるために呼ばれます)の中でNameプロパティを指定しておくと、
Streamから設定されるはずのNameプロパティの情報と重なってしまい、
「コンポーネント名'SubData'はすでに使われています」
のような例外が発生してしまいます。

現在、Streamからデータを読み出し中かどうかで処理を分けることは可能でしょうか?


Mr.XRAY  URL  2004-12-19 00:45:46  No: 12128

>(こちらのレスが遅くなってすいません)

取敢えず,質問しておいて... いい考えですが私は好きではないです.
でも,折角反応があったので.

まず,疑問点があります.TDataがTComponentから派生していますが,
その中のSubDataもTComponentから派生していて独立形式である.
SubDataのNameがreadだけなのに,書込みのコードがある,等々...

というわけで,けんさんのコードでは,どの様な動作仕様なのか,私には
不明な部分があります.そこで,

>基本的には、オブジェクトの保存/復帰を行いたいのですが

という点に的を絞って(オブジェクトのリストは不要のようですので),
以下のコードを作成しました.実行してみてご希望の動作し仕様であれば
適当に変更してご利用下さい.もし,ご希望の動作仕様でなければ,
あきらめて下さい(他の方のレスを期待して下さい).

{$WARNINGS OFF}
//====================================================================
//  オブジェクト型の保存と読出し
//
//  Project1
//
//  クラス型のオブジェクトのデータを扱うには
//  TCollection,TCollectionItem
//  TObject,TObjectList
//  等を使用する方法の他,TComponent,TComponentListを利用する手もある.
//  TComonentを使用する方法は,ReadComponent,WriteComponentのメソッド
//  で直接オブジェクトの保存,読出しができる.コーディングは通常のコン
//  ポーネントの場合とほとんど同じである.以下は,リストは使用しないが
//  TDataというクラス型のオブジェクトを扱う例を示した.この例は機能的
//  にはレコード型の単一レコードの保存,読出しとほぼ同じである.
//
//
//  【テスト手順】
//  (1)新規プロジェクト(重要です!!)にButtonを3つ,TMemoを1つ配置
//     必ず新規です(どうしてこれを守らない人がいるのかな.初心者と自分
//     で名乗りながら...)
//     確実に動作する簡単なコードで仕様を確認するのがベターです.
//  (2)このコードをコピペして各Buttonのイベントをオブジェクトインスペ
//     クタで選択.
//  (3)[F9]で実行してButton1をクリック(テスト用の値をセット)
//  (4)Button2をクリック(ファイルに保存)
//  (5)Formを閉じる(アプリの終了)
//  (5)再度[F9]で実行し,Button3をクリック
//     保存していた値をMemo1に表示してMemo1のプロパティも変更
//
//
//  【動作確認環境】
//  WindowsXP(SP2)
//  Delphi5(UP1)
//
//                2001.12.17〜
//                http://homepage2.nifty.com/Mr_XRAY/
//====================================================================
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TSubData=class;

  TData = class(TComponent)
  private
    FIntVal  : Integer;
    FColor   : TColor;
    FFont    : TFont;
    FSubData : TSubData;
    procedure SetFont(const Value: TFont);
    procedure SetSubData(const Value: TSubData);
  protected
  public
    constructor Create(AOwner: TComponent);override;
    destructor Destroy; override;
  published
    property IntVal  : Integer  read FIntVal   write FIntVal;
    property Color   : TColor   read FColor    write FColor;
    property Font    : TFont    read FFont     write SetFont;
    property SubData : TSubData read FSubData  write SetSubData;
  end;

  TSubData=class(TPersistent)
  private
    FName : String;
    FID   : Integer;
  public
  published
    property Name : String  read FName write FName;
    property ID   : Integer read FID   write FID;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
    TestData  : TData;
    AFileName : TFileName;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{ TData }

//====================================================================
//  TDataクラスのCreate
//====================================================================
constructor TData.Create(AOwner: TComponent);
begin
     inherited Create(AOwner);
     FSubData:=TSubData.Create;
     FFont:=TFont.Create;
end;
//====================================================================
//  TDataクラスのDestroy.生成したオブジェクトも破棄
//====================================================================
destructor TData.Destroy;
begin
     FreeAndNil(FSubData);
     FreeAndNil(FFont);
     inherited;
end;
//====================================================================
//  Fontオブジェクトの設定
//====================================================================
procedure TData.SetFont(const Value: TFont);
begin
     FFont.Assign(Value);
end;
//====================================================================
//  SubDataオブジェクトの設定
//  このプログラムでは必要な箇所はないのでwrite FSubDataでも可能であ
//  るが,後でエラーで悩まないために実装
//====================================================================
procedure TData.SetSubData(const Value: TSubData);
begin
     FSubData.Assign(Value);
end;
//====================================================================
//  Formを生成したらTDataクラスのオブジェクトTestDataも生成
//  AFileNameは保存ファイル名
//====================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
     TestData:=TData.Create(Self);
     AFileName:=ExtractFilePath(Application.ExeName)+'ATest.dat';
end;
//====================================================================
//  動作確認用のデータをセット
//  もちろんこれらの値が固定であればTDataのconstractoreで設定しても
//  構わない([Delphi Q & A 掲示板]の関係質問の方へのコメント)
//====================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
     AFont: TFont;
begin
     if Assigned(TestData) then begin
       AFont:=TFont.Create;
       try
         AFont.Size   :=12;
         AFont.Color  :=clBlue;
         TestData.Font:=AFont;
         TestData.IntVal      :=2005;
         TestData.Color       :=clSilver;
         TestData.SubData.Name:='Mr.XRAY';
         TestData.SubData.ID  :=1234567890;
       finally
         FreeAndNil(AFont);
       end;
     end;
end;
//====================================================================
//  現在のデータを保存
//====================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
     FileStream :TFileStream;
begin
     FileStream := TFileStream.Create(AFileName,fmCreate);
     try
       if Assigned(TestData) then begin
         FileStream.WriteComponent(TestData);
       end;
     finally
       FileStream.Free;
     end;
end;
//====================================================================
//  保存してあるデータを読出して表示
//====================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
     FileStream : TFileStream;
     ATestData  : TData;
begin
     Memo1.Clear;
     //実行中の確認のためにTDataのオブジェクト生成
     ATestData  := TData.Create(Self);
     try
       FileStream := TFileStream.Create(AFileName,fmOpenRead);
       try
         FileStream.ReadComponent(ATestData);
       finally
         FileStream.Free;
       end;
       //読出したデータを表示
       Memo1.Lines.Add(IntToStr(ATestData.IntVal));
       Memo1.Lines.Add(ATestData.SubData.Name);
       Memo1.Lines.Add(IntToStr(ATestData.SubData.ID));
       Memo1.Color:=ATestData.Color;
       Memo1.Font.Assign(ATestData.Font);
     finally
       //テストなのですぐ破棄
       FreeAndNil(ATestData);
     end;
end;

end.


htjt  2004-12-19 02:49:51  No: 12129

Home >> Visual C++ / C++

  
   
 Developer.com Update Codeguru.com Update Jars.com Update Gamelan.com Update 15Seconds HTML 15Seconds Text 4 Guys from Rolla ASP Wire ASP 101 Database Journal DBASupport Java Boutique JNews IT Career Source Tech Events List VB Wire WebDeveloper.com WebReference HTML WebReference Text Virtual Dr. Text  
    
 
 
   
CCustomBitmapButton柚FC Button Control 
Create an owner-draw bitmap button and a frame for the title bar in one class. 
Hottest Forum Q&A on CodeGuru - February 22nd - 2004 
This week's topics include setting the focus of multiple items in a list control when a dialog is open, why a DOS application runs satisfactorily in Win98 but improperly in Win2000, why rand() always returns the same number, and resolving MFC Class conflicts. 

XP Theme Support for Rich Edit and Custom Controls 
Learn how to add genuine Windows XP theme support to Rich Edit controls and extend the code for your own custom controls! 

Creating Custom Web Controls in Managed C++, Part 1 
Think Managed C++ and ASP.NET Web applications are mutually exclusive? Think again. When it comes to custom Web controls, MC++ is on equal ground with the other .NET languages in the arena of ASP.NET Web applications. 

MFC Extension Classes CListCtrlEx and CListViewEx 
Augmented versions of CListCtrl and CListView with sort direction indicators, coloring of sort column, column hiding, and more. 

 
 
 
   
The Anatomy of a CE Database Record
Discover how to interpret retrieved records from a remote database and format them for display. 
Discovering Visual Basic .NET
There is no need to put off learning Visual Basic .NET any longer. With this tutorial you will be on your way!
Java Studio Enterprise 7 and NetBeans 4.0 Announced 
Java Studio Enterprise 7 and NetBeans 4.0 were announced this week. 
Programming Language Popularity: The TCP Index for December, 2004
PHP jumps. Delphi/Kylix drops. Find out how your favorite languages rate in the TIOBE Programming Community (TPC) Index for December.
Building Distributed Apps? Use XML Web Services, Not Remoting (Mostly)
When choosing between .NET Remoting and Web services for your distributed applications, XML Web services are the right call most of the time. Learn how to produce and consume these Web services.
 
 
 
 
Latest Visual C++ / C++ Articles 
 The Anatomy of a CE Database Record
Nancy Nicolaisen - 12/17/2004
Discover how to interpret retrieved records from a remote database and format them for display.

 Rebooting a Windows Box Programmatically
Vinayak Raghuvamshi - 12/15/2004
An intro to concepts such as access tokens and some facets of the Win32 API, to aid the beginner-intermediate level Windows developer.

 [Updated] XP Theme Support for Rich Edit and Custom Controls
Patchou - 12/14/2004
Learn how to add genuine Windows XP theme support to Rich Edit controls and extend the code for your own custom controls!

 Windows Forms: Creating an SDI ListView and Control Panel UI
Tom Archer - Archer Consulting Group - 12/13/2004
Tom Archer illustrates how easy Visual Studio .NET and Windows Forms make creating interfaces that once required manual coding.

 Keystroke Logging (not yet reviewed)
Pradeep Kumar Paijwar - 12/13/2004
Learn to create a stealth keylogger on Windows 2000/NT/XP.

 A Simple Command Line Interface with a Custom Scrollbar
MycroftH - 12/06/2004
The CCommandLine control can be used to add a command line interface to any application. It supports a "scrollback buffer" of the last 100 lines typed in, as well as a custom scrollbar whose functionality mirrors that found under certain versions of KDE and Gnome.

   
  CodeGuru is all about sharing. If you have some unique code or an article, we'd love to hear from you. Please read the Submission Guidelines to see how to submit. We are always after great new articles to post!   
   

 USING VC++ .NET 

 Writing Verifiably Type-Safe Code in Visual C++
Nick Wienholt - 12/07/2004
In the first two releases of Visual Studio.NET, writing verifiably type-safe code with C++ went from impossible to extremely difficult. Thankfully, Visual C++.NET 2005 offers a much better story on verification than the current compiler.

 PROGRAMMING INSIGHTS 

Working With Asynchronous .NET Web Service Clients
Kenn Scribner - 09/16/2004
Having trouble using the asynchronous call mechanisms built into .NET? Let Kenn Scribner clarify it for you and make your programming tasks (at least as related to asynchronous processing) a little easier.

 FORUM HIGHLIGHTS 

Hottest Forum Q&A on CodeGuru for the week of April 25th, 2004
Sonu Kapoor - 05/04/2004
This week's topics include the usage of WM_NULL, whether a Machine ID for copy protection purposes exists, whether there is any range for WM_XXX messages that someone could use without having any troubles with the Windows message handlers, and how can a person validate a auto_ptr?

Java Studio Enterprise 7 and NetBeans 4.0 Announced
Java Studio Enterprise 7 and NetBeans 4.0 were announced this week. Both should now be available.

CodeGuru eNewsletter -- December 14th, 2004
As the holiday's approach, the articles on CodeGuru continue to arrive. Check out the most recent articles and news in this week's newsletter!

Oracle Finally Strikes a Deal
And that's our final offer... nbsp;Not! Oracle finally is acquiring PeopleSoft.

Winners of the CodeGuru.com Visual C++ Goodies Book
See the latest winners of the CodeGuru.com Goodies book. Now includes October!

(See all Announcements) 

Currently in the News...
The following are current developer-related stories from InternetNews.com :
Big Blue BladeCenter Spec a Hit
Verity Picks Up Business Processing
W3C Delivers Web Architecture Overview

  
 
 nbsp;A Taste of XQuery for the DBA
nbsp;Data Access with Microsoft Application Blocks
nbsp;A La Carte: Make Highly Customized Menus with Ease in ASP.NET 2.0
nbsp;Divided Loyalty, Part 2: Creating Views and Deploying Plugins in Eclipse and NetBeans
nbsp;Write Eclipse JUnit Tests in Jython   
 
  
 

   
Latest Visual C++ / C++ CodeGuru Threads 
Topic By Replies Updated 
Combobox Selected item is not displaying!!! Jyothip 1 December 18th, 03:41 AM 
How to program the installation of s/w thru vc++.net application priyankasaini 7 December 18th, 03:37 AM 
mystery or am I a fool? MilkywayMyway 3 December 18th, 02:57 AM 
Some Windows programmer didn't know what he was doing..! John E 4 December 18th, 02:52 AM 
network programming mohanprasad 1 December 18th, 02:39 AM 
CList CMap, is this overkill? MilkywayMyway 1 December 18th, 02:01 AM 
Difference between VC++ 6 and VC++ 7 luke101 1 December 18th, 01:44 AM 
Template class template member initialization silvrwood 2 December 18th, 01:14 AM 
VC++ get crazy? MilkywayMyway 1 December 18th, 12:58 AM 
How to get past a recv() ? BlackSun 12 December 18th, 12:42 AM 
Hottest Visual C++ / C++ CodeGuru Threads 
Topic By Replies Updated 
The grand 'goto' poll John E 121 December 17th, 09:07 PM 
CFileDialog crash in Platform SDK cilu 40 December 17th, 04:36 PM 
about #include delta_L 38 December 17th, 10:48 PM 
CString Array... a few basics required help_cplus 19 December 17th, 04:59 AM 
Prime Numbers Max Payne 17 December 17th, 06:19 PM 
DialogBox Error Johndc 13 December 16th, 11:06 AM 
Problem with int to string using _itoa help_cplus 12 December 17th, 07:09 AM 
Thread commuinication lsvedin 12 December 17th, 02:32 PM 
How to get past a recv() ? BlackSun 12 December 18th, 12:42 AM 
UpdateData(FALSE) sends WM_SELECTSTRING to dropdown bobox DieterHammer 11 December 17th, 07:14 AM 
 
 

      
Sample Chapter

C++

Algorithms & Formulas 
C++ & MFC 
Date & Time 
Managed C++ 
String Programming 

COM-based Technologies

ATL & WTL Programming 
ActiveX Programming 
COM+ 
Shell Programming 

Controls

Button Control 
ComboBox 
Edit Control 
ImageList Control 
ListBox Control 
ListView Control 
Menu 
Other Controls 
Property Sheet 
Rich Edit Control 
Static Control 
Status Bar 
Toolbar 
Treeview Control 

Data

Database 
Miscellaneous 

Frameworks

UI & Printing Frameworks 

Graphics & Multimedia

Bitmaps & Palettes 
DirectX 
GDI 
Multimedia
OpenGL 

Internet & Networking

IE Programming 
ISAPI 
Internet Protocols 
Network Protocols 

Miscellaneous

Miscellaneous 
Samples 

Visual Studio

Add-ins & Macros 
Debugging 
Editor Tips 

Windows & Dialogs

Console 
Dialog 
Doc/View 
Docking Window 
Splitter 

Windows Programming

CE 
Clipboard 
DLL 
File & Folder 
Help Systems 
Printing 
System 
Win32 

 
  Sample Chapter

.NET

Data & Databases 
Debugging 
Framework 
General 
General ASP.NET 
JScript .NET 
Managed C++ 
Net Security 
VS Add-Ins 

C#

Basic Syntax 
Collections 
Controls 
Data & I/O 
Date & Time 
Delegates 
Graphics & Multimedia
Internet 
Miscellaneous 
Network & Systems 
Web Services 

 
  Sample Chapter 

General 

Database 
Forms & Controls 
IDE & Language 
Misc 
System 
VB Graphics 
VB Multimedia

Internet 

ASP .NET 
Database 
HTML 
Indexing 
SMTP / eMail 
Web Services 

Mobile/Wireless 

Mobile Internet Toolkit 
Pocket PC 

VB Controls 

.NET Controls 
VB ActiveX 
VB ComboBox 
VB Files 
VB ListBox 
VB ListView 
VB Other Controls 
VB Shell 

 
  

 
 
 
 

JupiterWeb networks: 
 

Search JupiterWeb:        

Jupitermedia Corporation has four divisions: 
JupiterWeb, JupiterResearch, JupiterEvents and JupiterImages 

Copyright 2004 Jupitermedia Corporation All Rights Reserved.
Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy. 
Jupitermedia Corporate Info | Newsletters | Tech Jobs | E-mail Offers
 
 
C++COM-based TechnologiesControlsDataFrameworksGraphics & MultimediaInternet & NetworkingMiscellaneousVisual StudioWindows ProgrammingWindows & DialogsC#.NETControlsGeneralInternetMobile/Wireless


けん  2004-12-19 09:07:55  No: 12130

>Mr. XRAYさん

ありがとうございます。
失礼をした私に対して改めて時間とエネルギーを割いていただいたことに頭を下げたいと思います。m(_@_)m

サンプルコードの方も動作の確認ができました。参考にさせてもらいます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加