全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1292
推到 Plurk!
推到 Facebook!

如何使用WriteComponent儲存內含TList的物件

尚未結案
shychef
一般會員


發表:5
回覆:10
積分:3
註冊:2004-10-02

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-08-02 16:44:18 IP:211.23.xxx.xxx 未訂閱
各位大大: 小人在下我建立一個Class如下: //------------prjdata.h-------------- class TPrj : public TComponent { private: AnsiString FPrj_Name; AnsiString FPrj_Comment; public: TList *pTaskList; __fastcall TPrj(AnsiString); __fastcall TPrj(); __fastcall ~TPrj(); __published: __property AnsiString Prj_Name = {read=FPrj_Name, write=FPrj_Name}; __property AnsiString Prj_Comment = {read=FPrj_Comment , write=FPrj_Comment}; }; 當按下button2後,則用WriteComponent將aPrj物件儲存起來 當按下button3後,則用ReadComponent將物件內容丟到bPrj物件儲存起來 //------------project.cpp-------------- TPrj* aPrj=new TPrj(); void __fastcall TMDIChild::Button2Click(TObject *Sender) { TMemoryStream* buffer= new TMemoryStream(); buffer->WriteComponent(aPrj); buffer->SaveToFile("save.dat"); delete buffer; } TPrj* bPrj; void __fastcall TMDIChild::Button3Click(TObject *Sender) { bPrj = new TPrj(); TMemoryStream* buffer = new TMemoryStream() ; try{ buffer->Position = 0; buffer->LoadFromFile("asd.chr"); buffer->ReadComponent(bPrj); } __finally{ delete buffer,bPrj; } } 程式到目前為止都是正常無誤的,可正常寫入,也可正常讀出。 現在問題來了。 在class TPrj 中有一個TList *pTaskList; pTaskList裏面裝的又是一個類別,內容如下: 很明顯的,當我使用WriteComponent時,是無法將這個TList裏裝的類別的資料也一起儲存。 用DefineProperties有辦法解決嗎?請大大們為不才解惑 //------------taskdata.h-------------- class TTask : public TComponent { private: AnsiString FTsk_Name; AnsiString FTsk_Type; public: TList *pPouList; __fastcall TTask(AnsiString); __fastcall ~TTask(); __published: __property AnsiString Tsk_Name = {read=FTsk_Name, write=FTsk_Name}; __property AnsiString Tsk_Type = {read=FTsk_Type, write=FTsk_Type}; };
taishyang
站務副站長


發表:377
回覆:5490
積分:4563
註冊:2002-10-08

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-08-02 18:14:28 IP:210.68.xxx.xxx 未訂閱
您好:    PO程式碼的方式與版規說明請參考下面連結,煩請修改謝謝您的配合 >
justdo
高階會員


發表:2
回覆:359
積分:222
註冊:2004-08-17

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-08-02 20:11:56 IP:221.169.xxx.xxx 未訂閱
TList 裡面存放 void* 的東西,顯然無法透過這種指標獲知內部存放的東西到底是什麼,建議換個容器來存放,另外,你是存放什麼東西的指標? 另外,你的程式我編不起來(真是慚愧... ) TPrj型別繼承TComponent,當產生新物件時TComponent需要一個TComponent* Owner,你是怎麼給他的? 還有我覺得你光是用 buffer->WriteComponent(aPrj); 並不會儲存FPrj_Name跟FPrj_Comment這兩個物件 從文件上看來,應該要 override WriteState() 然後在這個函式內寫好儲存TPrj內部成員的程式碼 不過我測試的類別想繼承TComponent都失敗,所以無從測起...
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-08-03 01:20:10 IP:219.84.xxx.xxx 未訂閱
TList並不包含在Delphi定義的property資料型,無法用WriteComponent存。 可以用的資料型可以參考以下的程式片斷:     
 
switch(TypeKind)
        {
        case tkUnknown:
                return "Unknown";
        case tkInteger:
                return "Integer";
        case tkChar:
                return "Char";
        case tkEnumeration:
                return "Enumeration";
        case tkFloat:
                return "Float";
        case tkString:
                return "String";
        case tkSet:
                return "Set";
        case tkClass:
                return "Class";
        case tkMethod:
                return "Method";
        case tkWChar:
                return "WideChar";
        case tkLString:
                return "LongString";
        case tkWString:
                return "WideString";
        case tkVariant:
                return "Variant";
        case tkArray:
                return "Array";
        case tkRecord:
                return "Record";
        case tkInterface:
                return "Interface";
        case tkInt64:
                return "Int64";
        case tkDynArray:
                return "DynArray";
}
shychef
一般會員


發表:5
回覆:10
積分:3
註冊:2004-10-02

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-08-03 09:09:05 IP:211.23.xxx.xxx 未訂閱
TO:taishyang副站長 我已經將發表內容修改了 應該有符合發表規則了。 謝謝副站長的提醒
shychef
一般會員


發表:5
回覆:10
積分:3
註冊:2004-10-02

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-08-03 09:56:30 IP:211.23.xxx.xxx 未訂閱
TO: justdo前輩 謝謝您的回應 ??----- TPrj型別繼承TComponent,當產生新物件時TComponent需要一個TComponent* Owner,你是怎麼給他的? //------ 產生新物件時,它的owner我是設NULL ??--------- TList存的是什麼指標? //---------- TList 裏面存的指標是一個指向TTask(我自訂的)的物件。 為了簡化我的問題,所以貼出來的程式碼是經過精簡過的, 所以有些地方沒交待那麼清楚,非常抱歉。 其實我要寫的是一個編輯器,使用者可建立一個project。 這個project中可管理多個task,使用者可在每個task建立network區塊編輯程式。 我之所以會繼承TComponent,主要就是為了使用WriteComponent, 因為我想把整個project當成一個物件,當使用者要儲存編輯內容時就將整個元件儲存起來就好了。 我有上傳一張示意圖,如下,大大們看了應該就會比較明白我問的問題。 http://140.115.80.13/~shychef/question.jpg 另外,我的屬性都有寫在__published:下面,所以SaveToFile及LoadFromFile,都是正常的。 TList* pTaskList這個搞不定。 發表人 - shychef 於 2005/08/03 10:56:04 發表人 - shychef 於 2005/08/03 11:05:45
shychef
一般會員


發表:5
回覆:10
積分:3
註冊:2004-10-02

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-08-03 10:24:08 IP:211.23.xxx.xxx 未訂閱
TO:pwipwi前輩 依您所說: TList並不包含在Delphi定義的property資料型,無法用WriteComponent存。 但是否有辦法用DefineProperties克服。 下面是我一個朋友在六年前寫的,因為已經跟他失聯,所以沒法子請叫他。 不知前輩對下列的程式有何看法。    注意最後那行   __property TMemoryStream *Body={read=GetBody, write=SetBody};    在產生C4MsgAppendix物件後,就可以用 xxx->Body->Memory    
class  PACKAGE TC4MsgAppendix : public TComponent
{
private:
  // property variable declaration
  AnsiString FCatalog;    // 判斷類別及編號
  AnsiString FReference;  // 參考資料
  int        FKind;       // 配佈
  TMemoryStream *FBody;   // 訊息實體      // property method declaration
//----------------
  TMemoryStream* __fastcall GetBody(void)
  {
    if (FBody == NULL)
      FBody = new TMemoryStream;
    return FBody;
  };
  void __fastcall SetBody(TMemoryStream *Value)
  {
    if (FBody && Value) {
      FBody->LoadFromStream(Value);
    }
  };    //----------------
  void __fastcall ReadData(TStream* Stream)
  {
    Body->LoadFromStream(Stream);
  };
  void __fastcall WriteData(TStream* Stream)
  {
    Body->SaveToStream(Stream);
  };
//----------------
  int __fastcall GetKind(void)
  {
    return FKind;
  };
  void __fastcall SetKind(int Value)
  {
    FKind = Value;
  };    public:
  __fastcall TC4MsgAppendix() : TComponent(NULL) {};
  virtual void __fastcall DefineProperties(TFiler* Filer)
  {
    Filer->DefineBinaryProperty("Body->Memory", ReadData, WriteData, true);
  }
__published:
  __property AnsiString Catalog={read=FCatalog, write=FCatalog};
  __property AnsiString Reference={read=FReference, write=FReference};
  __property int Kind={read=GetKind, write=SetKind, default = 0};
  __property TMemoryStream *Body={read=GetBody, write=SetBody};
}; 
最後,為什麼我上傳一張圖檔不會出現? 好奇怪哦! 有顯示上傳成功耶
justdo
高階會員


發表:2
回覆:359
積分:222
註冊:2004-08-17

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-08-04 21:52:13 IP:221.169.xxx.xxx 未訂閱
同上一篇文章可以用 DefineProperty 定義處理 pPouList 的兩個函式 然後分別處理 ReadComponent 和 WriteComponent 時對 pPouList 該如何處理    若你 TTask 有繼承 TComponent,那麼應該在處理 WriteComponent 時,將pPouList內部的元素一一呼叫 Writer->WriteComponent(pPouList->Items[i])即可 若沒有繼承 TComponent,只是簡單的 struct,則直接用 Writer->Write 就行了,以下是測試程式
#include 
#include     class TTask
{
public:
  int first;
  int second;
};    class TPrj : public TComponent
{
private:
  AnsiString FTsk_Name;
  AnsiString FTsk_Type;
  void __fastcall LoadCompProperty(TReader *Reader);
  void __fastcall StoreCompProperty(TWriter *Writer);    protected:
  virtual void __fastcall DefineProperties(TFiler *Filer);    public:
  TList* pPouList;
  TPrj(AnsiString);
  __fastcall ~TPrj(void) {}    __published:
  __property AnsiString Tsk_Name = {read=FTsk_Name, write=FTsk_Name};
  __property AnsiString Tsk_Type = {read=FTsk_Type, write=FTsk_Type};
};    TPrj::TPrj(AnsiString a):TComponent(NULL)
{
        pPouList=NULL;
}    void __fastcall TPrj::LoadCompProperty(TReader *Reader)
{
  if (Reader->ReadBoolean())
  {
    if (pPouList == NULL)
      pPouList=new TList;
    TTask* t=new TTask;
    Reader->Read(t, sizeof(TTask));
    pPouList->Add((void*)t);
  }
}    void __fastcall TPrj::StoreCompProperty(TWriter *Writer)
{
  if (pPouList)
  {
    Writer->WriteBoolean(true);
    Writer->Write(pPouList->Items[0], sizeof(TTask));
  }
  else
    Writer->WriteBoolean(false);
}    void f_save()
{
        TPrj* a=new TPrj("00");
        a->Tsk_Name = "123";
        a->Tsk_Type = "456";            a->pPouList = new TList;
        TTask b;
        b.first=1;
        b.second=2;
        a->pPouList->Add((void*)&b);            TMemoryStream* buffer= new TMemoryStream();
        buffer->WriteComponent(a);
        char* ptr=(char*)(buffer->Memory);
        buffer->SaveToFile("save.dat");
}    void f_load()
{
        TPrj* a=new TPrj("00");
        TTask* b;
        TMemoryStream* buffer= new TMemoryStream();
        buffer->Position = 0;
        buffer->LoadFromFile("save.dat");
        char* ptr=(char*)(buffer->Memory);
        buffer->ReadComponent(a);
        delete buffer;
        AnsiString p;
        AnsiString q;
        p=a->Tsk_Name;
        q=a->Tsk_Type;
        cout << p.c_str() << ", " << q.c_str() << endl;            b=(TTask*)a->pPouList->Items[0];
        p=b->first;
        q=b->second;
        cout << p.c_str() << ", " << q.c_str() << endl;
}    void __fastcall TPrj::DefineProperties(TFiler *Filer)
{
  TComponent::DefineProperties(Filer);
  Filer->DefineProperty("pPouList",LoadCompProperty,StoreCompProperty, true);
}    int main()
{
        f_save();
        f_load();
        system("pause");
}
備註:以上程式碼未最佳化、也未歸還使用的記憶體、僅考慮TList含有一個元素而已
shychef
一般會員


發表:5
回覆:10
積分:3
註冊:2004-10-02

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-08-09 08:52:43 IP:211.23.xxx.xxx 未訂閱
謝謝幾位大大幫我解決問題, 特別是pwipwi及justdo大大。 因為我覺得justdo大大提供的解決方法是可行的, 而這個是我第一次在ktop發問, 所以第一次就給justdo前輩。 記得要包紅包給我喔。
系統時間:2024-05-09 12:50:29
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!