b. パーツFileXYの修正

1.WorkFrame IDEアイコンをクリックし、「既存のオブジェクトを

  オープンします」をクリックする。

  DataColl.IWPをダブルクリックする。

2.WorkFrameのDataCol.vbbをダブルクリックして、ビジュアル・ビルダーを開く。

3.非ビジュアル・パーツのFileXYをダブルクリックする。

4.クラス・エディターの必要なインクルード・ファイルに、"Comment.hpp" _COMMENT_

  を追加する。

5.パーツ・インターフェース・エディターに下記の項目を追加する。

FileXYパーツの追加

属性

タイプ

コメント

優先

commentItems

IVSequence<Comment*>*

コメントをシーケンシャルに収納する

O

set関数の引数のconstを削除

addComment

IString

指定したフォーマットでコメントを書く場合は、文字列yesを代入する

O

イベント

コメント

優先

exportToFileAddComment

セーブするコメントのフォーマットを指定していることを通知する

O

importFromFileAddComment

指定したフォーマットのコメントが有ることを通知する

O

6.「ファイル」->「保管および生成」->「フィーチャー・ソース」をクリックする。

7.「FileXY−フィーチャー・ソース・コードを作成します」ダイアログにおいて、

  メンバー関数の

   virtual IString addComment() const

   virtual IVSequence<Comment*>* commentItems() const

   virtual FileXY& setAddComment( const IString& aAddComment )

   virtual FileXY& setCommentItems( IVSequence<Comment*>* aCommentItems )

  属性データ・メンバーの

   iAddComment

   iCommentItems

  イベント・データ・メンバー

   addCommentId

   commentItemsId

   exportToFileAddCommentId

   importFromFileAddCommentId

  をCtrlキーを押しながらクリックして、選択する。

8.「選択したものの生成」をクリックして、FileXY.cpvとFileXY.hpvに

  上記の項目を追加する。

9.FileXY.hpvに以下が自動的に追加される。

// Feature source code generation begins here...
public:
virtual IVSequence<Comment*>* commentItems() const;
virtual FileXY& setCommentItems(IVSequence<Comment*>* aCommentItems);
virtual IString addComment() const;
virtual FileXY& setAddComment(const IString& aAddComment);
 
static const INotificationId IVB_IMPORT commentItemsId;
static const INotificationId IVB_IMPORT exportToFileAddCommentId;
static const INotificationId IVB_IMPORT importFromFileAddCommentId;
static const INotificationId IVB_IMPORT addCommentId;
 
private:
IVSequence<Comment*>* iCommentItems;
IString iAddComment;
// Feature source code generation ends here.

10.FileXY.hpvに以下のコードを入力する。

// User's source code generation begins here...
protected:
IString iCommentImported;
virtual void userConstructor();
// User's source code generation ends here.

11.セーブする。

12.FileXY.cpvを下記のように修正する。

long FileXY::exportToFile(const IString& filename)
{
 ofstream ofStream;
 DataXY* iExportItem;
 long iCount=0;
 IVSequence<DataXY*>::Cursor SeqCursor( *iItems );
 IVSequence<Comment*>::Cursor CommentCursor( *iCommentItems ); //
変更箇所
 Comment* iComment; //
変更箇所
 
 //
変更開始箇所
 if( iAddComment=="yes" ) // 指定されたフォーマットでコメントを記入する場合
 {
  notifyObservers(INotificationEvent(FileXY::exportToFileAddCommentId, *this));
  ofStream.open( filename, ios::app ); // 既存のデータに継ぎ足す
 }
 else
 {
  if( iCommentImported=="yes" ) // 他のフォーマットでコメントが記入されている場合
  {
   ofStream.open( filename );
   CommentCursor.setToFirst(); // コメントの最初の項にセット
   while( CommentCursor.isValid() ) // コメントが存在する間、繰り返す
   {
    // コメントのカーソル位置のテキストをiCommentに代入する
    iComment = iCommentItems->elementAt( CommentCursor );
    // クラスCommentのtextをファイルにセーブする
    ofStream << iComment->text() << endl;
    CommentCursor.setToNext(); // 次の項に移る
   }
  }
  else // コメントがない場合
  {
   ofStream.open( filename ); // ファイルのオープン
  }
 }
 //
変更箇所終了

 if( !ofStream ) // 例外処理
 {
  IString errorText = IString( "ファイル" ) + filename + "をオープンできません。";
  IException exc( errorText, 0, IException::unrecoverable );
  ITHROW( exc );
 } // 例外処理終了
 
 if( iType=="comma" ) // データ間をコンマで区切る場合
 {
  for( SeqCursor.setToFirst(); SeqCursor.isValid(); SeqCursor.setToNext() )
  {
   iExportItem = iItems->elementAt( SeqCursor );
   ofStream << iExportItem->dataX() << "," << iExportItem->dataY() << endl;
   iCount++;
  }
 }
 if( iType=="space" ) // データ間をスペースで区切る場合
 { 
  for( SeqCursor.setToFirst(); SeqCursor.isValid(); SeqCursor.setToNext() )
  {
   iExportItem = iItems->elementAt( SeqCursor );
   ofStream << iExportItem->dataX() << " " << iExportItem->dataY() << endl;
   iCount++;
  }
 }
 ofStream.close(); // ファイルのクローズ
 return iCount;
}
 
long FileXY::importFromFile(const IString& filename)
{
 ifstream ifStream;
 DataXY* iImportItem;
 Comment* iCommentItem; //
変更箇所
 long iCount=0;
 double iDataX;
 double iDataY;
 char iCharacter;
 IString iText;
 long iMark; //
変更箇所
 
 ifStream.open( filename ); // ファイルのオープン
 
 if( !ifStream ) // 例外処理
 {
  IString errorText = IString( "ファイル" ) + filename + "をオープンできません。";
  IException exc( errorText, 0, IException::unrecoverable );
  ITHROW( exc );
 } // 例外処理終了
 
 //
変更開始箇所
 if( ifStream.get()=='%' ) // 頭文字が'%'の場合
 {
  ifStream.close(); // コメントが有るため、一旦ファイルを閉じる
  // コメントが有ることを知らせる
  notifyObservers(INotificationEvent(FileXY::importFromFileAddCommentId, *this));
  // コメントがインポートされたことを示す
  iCommentImported = IString( "yes" );
 }
 else
 {
  ifStream.close(); // 一旦ファイルを閉じる
  // コメントがないことを示す
  iCommentImported = IString( "no" );
 }
 
 // コメントの処理を終えて、データを入力するために再びファイルを開く
 ifStream.open( filename ); // ファイルのオープン
 if( !ifStream ) // 例外処理
 {
  IString errorText = IString( "ファイル" ) + filename + "をオープンできません。";
  IException exc( errorText, 0, IException::unrecoverable );
  ITHROW( exc );
 } // 例外処理終了
 
 // commentItemsのイベント通知機能を禁止
 iCommentItems->disableNotification();
 
 iMark = ifStream.tellg(); // ifStreamの最初の行番号を代入する
 iText = IString::lineFrom( ifStream ); // 最初の行のテキストを代入する
 // 文字列の最初の文字を取り出し、"%"と比較する
 while( iText.subString(1,1) =="%" )
 {
  // クラスCommentのiCommentItemの実体(オブジェクト)を作成
  iCommentItem = new Comment;
  // iCommentItemにiTextを代入する
  iCommentItem->setText( iText );
  iCommentItems->addAsLast( iCommentItem ); // コメントに追加する
  iMark = ifStream.tellg(); // ifStreamの現在の行番号を代入する
  iText = IString::lineFrom( ifStream ); // 現在の行のテキストを代入する
 }
 // commentItemsのイベント通知機能を開始
 iCommentItems->enableNotification();
 // commentItemsのイベントを通知する。
 notifyObservers(INotificationEvent(FileXY::commentItemsId, *this));
 
 ifStream.seekg( iMark ); // データが書き込まれている行に移す
 //
変更箇所終了

 // itemsのイベント通知機能を禁止
 iItems->disableNotification();
 
 if( iType=="comma" ) // データ間をコンマで区切る場合
 {
  // 最後のデータまで繰り返す。
  while( !ifStream.eof() )
  {
   // DataXY型のiImportItemの実体(オブジェクト)を生成
   iImportItem = new DataXY;
   // ファイルからデータをdataX、コンマ、dataYの順に取り出す。
   ifStream >> iDataX >> iCharacter >> iDataY;
   // iImportItemにdataXとdataYを代入する。
   iImportItem->setDataX( iDataX );
   iImportItem->setDataY( iDataY );
   // iItemsの最後に加える。
   iItems->addAsLast( iImportItem );
   iCount++;
  }
 }
 if( iType=="space" ) // データ間をスペースで区切る場合
 {
  // 最後のデータまで繰り返す。
  while( !ifStream.fail() ) // ifStream.eof()と同じ
  {
   // DataXY型のiImportItemの実体(オブジェクト)を生成
   iImportItem = new DataXY;
   // ファイルからデータをdataX、dataYの順に取り出す。
   ifStream >> iDataX >> iDataY;
   // iImportItemにdataXとdataYを代入する。
   iImportItem->setDataX( iDataX );
   iImportItem->setDataY( iDataY );
   // iItemsの最後に加える。
   iItems->addAsLast( iImportItem );
   iCount++;
  }
 }
 // itemsの最後のオブジェクトのポインターを取得する。
 // このままでは、最後のデータが2回入るため。
 iImportItem = iItems->lastElement();
 // オブジェクトのポインターを削除する。
 iItems->removeLast();
 // オブジェクトを削除する。
 delete iImportItem;
 iCount -=1;
 
 ifStream.close(); // ファイルのクローズ
 
 // itemsのイベント通知機能を開始
 iItems->enableNotification();
 // itemsのイベントを通知する。
 notifyObservers(INotificationEvent(FileXY::itemsId, *this));
 return iCount;
}
 
long FileXY::save()
{
 return exportToFile( iItemsFilename ); // exportToFileを実行する。
}
 
long FileXY::saveAs(const IString& filename)
{
 long iCount;
 
 setItemsFilename( filename ); // 変更したファイル名を記憶する。//
変更箇所
 iCount = exportToFile( filename ); // ファイルへ保存
 return iCount;
}
 
long FileXY::open(const IString& filename)
{
 long iCount;
 
 newFile(); // 既存のデータをすべて削除する。
 setItemsFilename( filename ); // 開いたファイル名を記憶する。//
変更箇所
 iCount = importFromFile( filename ); // ファイルから読み込む。
 return iCount;
}
 
void FileXY::newFile()
{
 
 // itemsの全ての項目がなくなるまで繰り返す。
 while( !iItems->isEmpty() )
 {
  // itemsの最初のオブジェクトのポインターを取得する。
  DataXY* iImportItem = iItems->firstElement();
  // オブジェクトのポインターを削除する。
  iItems->removeFirst();
  // オブジェクトを削除する。
 delete iImportItem;
 }
 
 //
変更開始箇所
 // commentItemsの全ての項目を削除する。
 if( !iCommentItems->isEmpty() )
 {
  // commentItemsの最初のオブジェクトのポインターを取得する。
  Comment* iCommentItem = iCommentItems->firstElement();
  // オブジェクトのポインターを削除する。
  iCommentItems->removeFirst();
  // オブジェクトを削除する。
  delete iCommentItem;
 }
 //
変更箇所終了

 return;
}
// Feature source code generation ends here.

//
変更開始箇所
// User's source code generation begins here...
void FileXY::userConstructor()
{
 IVSequence<Comment*>* initialItems;
 
 // commentItemsにアクセスできるように、IVSequence<Comment*>型のオブジェクトを生成
 // IVSequence<Comment*>型のinitialItemsのオブジェクトを生成
 initialItems = new IVSequence<Comment*>;
 // CommenttemsにinitialItemsを代入
 setCommentItems( initialItems );
 
 iCommentImported = IString( "no" ); // 初期化
}
// User's source code generation ends here.
 //
変更箇所終了

13.セーブする。

14.FileXY−クラス・エディターのユーザー・コンストラクター・コードに

   userConstructor();

   と入力する。

   このパーツが呼び出されたとき、まずuserConstructor()を処理する。

   注意:必ず、userConstructor()の後に、; を書くこと、

15.「ファイル」->「保管」をクリックする。

16.今後パーツFileXYを利用できるように、覚え書きFileXY.htmlを

   下記のように修正する。

パーツFileXYの説明

2次元(x, y)データをセーブおよびロードするためのパーツである。

FileXYパーツ

属性

タイプ

コメント

優先

itemsFilename

IString

ファイル名の設定

O

type

IString

データ間の区切り方

commentまたはspace

O

items

IVSequence<DataXY*>*

全データをシーケンシャルに収納する

O

set関数の引数のconstを削除

commentItems

IVSequence<Comment*>*

コメントをシーケンシャルに収納する

O

set関数の引数のconstを削除

addComment

IString

指定したフォーマットでコメントを書く場合は、文字列yesを代入する

O

イベント

 

 

exportToFileAddComment

セーブするコメントのフォーマットを指定していることを通知する

O

importFromFIleAddComment

指定したフォーマットのコメントが有ることを通知する

O

アクション

タイプ

パラメータ

 

exportToFile

long

const IString& filename

importFromFile

long

const IString& filename

save

long

 

O

saveAs

long

const IString& filename

O

open

long

const IString& filename

O

newFile

void

 

O

 

データのセーブの仕方

 1.データ間をコンマで区切る場合は、属性typeを文字列commaにする。例:1.3,6.54

2.データ間をスペースで区切る場合は、属性typeを文字列spaceにする。例:1.3 6.54

 

ファイルを開くにはopen( filename )、データの上書保存にはsave ()、データの別名保存は

saveAs( filename )を用いる。

 

指定したフォーマットでコメントを記入する場合は、属性addCommentに文字列yesを

代入する。

ファイルに書き込む場合は、イベントexportToFileAddCommentとコメントを書き込む

パーツのアクションexportToFileとを接続する。

ファイルから読み込む場合は、イベントimportFromFileAddCommentとコメントを読み込む

パーツのアクションimportFromFileとを接続する。

必要なファイル

DataColl.vbb

FileXY.cpv

FileXY.hpv

 

DataXY.cpv

DataXY.hpv

 

Comment.cpv

Comment.hpv