《Delphi深度探索》里有一章有所讲解,楼主可以看看

解决方案 »

  1.   

    你有没有类似这方面的经验,我是做C++ BUILDER的,我写了代码,但不能达到我的要求,能给点提示吗?
      

  2.   

    {定义Field为一个String属性}type
      TFieldsProperty = class(TStringProperty)
      public
        procedure GetValues(Proc: TGetStrProc); override;
        function GetAttributes: TPropertyAttributes; override;
      end;...{ TFieldsProperty }procedure TFieldsProperty.GetValues(Proc: TGetStrProc);
    var Values: TStrings;
    begin
      Values := TStringList.Create; 
      FYourDataSet.GetFieldNames(Values);
      for I := 0 to Values.Count - 1 do
      begin
        Proc(Values[I]);
      end;
      Values.Free;
    end;function TFieldsProperty.GetAttributes: TPropertyAttributes;
    begin
      Result := [paValueList,paSortList,paMultiSelect];
    end;{注册}
    procedure Register;
    begin
      ...
      RegisterPropertyEditor(TypeInfo(String), TYourComponentClass, 'Field', TFieldsProperty);
    end;
      

  3.   

    谢谢楼上的回复,我现在需要知道的关键就是FYourDataSet是如何得到的呢?
    我写的是C++ BUILDER的代码,它们是两个不同的类,即是说控件类和属性编辑器类,而FYOURDATASET正好是关键之所在,它在控件类的private域中。说到底关键是我要知道如何在属性编辑器的类中得到当前的数据源?
      

  4.   

    谢谢楼上的回复,我现在需要知道的关键就是FYourDataSet是如何得到的呢?
    我写的是C++ BUILDER的代码,它们是两个不同的类,即是说控件类和属性编辑器类,而FYOURDATASET正好是关键之所在,它在控件类的private域中。说到底关键是我要知道如何在属性编辑器的类中得到当前的数据源?
      

  5.   

    (GetComponents(0) as TYourClass).DataSet....
      

  6.   

    //前提这两个类必须在一个pascal单元,因为你的DataSet为私有属性。//如果是c++builder,则必须publish你的DataSet。procedure TFieldsProperty.GetValues(Proc: TGetStrProc);
    var Values: TStrings;
        ADataSet: TDataSet;
    begin
      ADataSet := TYourComponent(GetComponent(0)).YourDataSet;
      Values := TStringList.Create; 
      ADataSet.GetFieldNames(Values);
      for I := 0 to Values.Count - 1 do
      begin
        Proc(Values[I]);
      end;
      Values.Free;
    end;
      

  7.   

    第二个问题基本解决了。
    关于第一个问题:
    To Borlandor:
    但凡是从TStringProperty继承下来的属性编辑器好像都没有下拉列表框,你可以试试。
      

  8.   

    有啊!关键是你要实现GetValues和注册属性编辑类。假设你的Component有如下属性:
    property Field: String read FField write FField;注册时PropertyName必须为'Field':
    RegisterPropertyEditor(TypeInfo(String), TYourComponentClass, 'Field', TFieldsProperty);
      

  9.   

    而且要实现GetAttributes,返回集合应包括paValueList。function TFieldsProperty.GetAttributes: TPropertyAttributes;
    begin
      Result := [paValueList,paSortList,paMultiSelect];
    end;
      

  10.   

    对啊,我已经重载了GetAttributes和GetValues方法,但在控件中仍见不到下拉列表框(但从整型属性编辑器继承就可以):下面是代码:
    //---------------------------------------------------------------------------#ifndef DataComBoxH
    #define DataComBoxH
    //---------------------------------------------------------------------------
    #include <SysUtils.hpp>
    #include <Controls.hpp>
    #include <Classes.hpp>
    #include <Forms.hpp>
    #include <StdCtrls.hpp>
    #include <dsgnintf.hpp>
    #include <db.hpp>
    #include <forms.hpp>
    #include <dialogs.hpp>//---------------------------------------------------------------------------class PACKAGE TDataComBox : public TComboBox
    {
    private:
            TDataSource* FDataSource;
            AnsiString FDataField;
            int FBaudRate;
            AnsiString FFileName;
    protected:
    public:
            void __fastcall SetDataSource(TDataSource* DataSource);
            void __fastcall SetDataField(AnsiString Field);
            void __fastcall SetBaudRate(int BaudRate);
            void __fastcall SetFileName(AnsiString FileName);
            __fastcall TDataComBox(TComponent* Owner);
    __published:
            __property TDataSource* DataSource={read=FDataSource,write=SetDataSource};
            __property AnsiString DataField={read=FDataField,write=SetDataField};
            __property int BaudRate={read=FBaudRate,write=SetBaudRate,default=9600};
            __property AnsiString FileName={read=FFileName,write=SetFileName};
            
    };
    //The following PropertyEditor is used by control to generate a listbox--Property:DataField
    class TDataFieldProperty:public TStringProperty
    {
    public:
       TPropertyAttributes __fastcall GetAttributes()
       {
            return TPropertyAttributes()<<paValueList<<paSortList;
       }
       void __fastcall GetValues(TGetStrProc Proc)
       {
            TDataSet *pDataSet;
            TDataComBox *pDCBX=dynamic_cast<TDataComBox*>(GetComponent(0));
            if(pDCBX)
            {       pDataSet=pDCBX->DataSource->DataSet;
                    if(pDataSet)
                    {
                            for(int i=0;i<pDataSet->FieldCount;i++)
                            {
                                    Proc(pDataSet->Fields->Fields[i]->FieldName);
                            }
                    }
            }
       }
    };
    //The following PropertyEditor is used by control to generate a listbox------Property:BaudRate
    class TBaudRateProperty:public TIntegerProperty
    {
    public:
            TPropertyAttributes __fastcall  GetAttributes()
            {
                    return TPropertyAttributes()<<paValueList;
            }
            void __fastcall GetValues(TGetStrProc Proc)
            {
                    Proc("9600");
                    Proc("14400");
                    Proc("28800");
                    Proc("32400");
                    Proc("57600");
            }
    };
    //The following PropertyEditor is used by control to generate a listbox-----Property:FileName
    class TFileNameProperty:public TStringProperty
    {
    public:
        TPropertyAttributes __fastcall GetAttributes()
        {
            return TPropertyAttributes()<<paDialog;
        }
        void __fastcall Edit()
        {
            TOpenDialog *O=new TOpenDialog(Application);
            O->Title="Kingcaiyao http://www.csdn.net";
            O->InitialDir="c:\\";
            O->FileName=GetValue();
            if(O->Execute())
            {
                    Value=O->FileName;
            }
            delete O;
        }
    };//---------------------------------------------------------------------------
    #endif
    .cpp File
    //---------------------------------------------------------------------------#include <vcl.h>
    #pragma hdrstop#include "DataComBox.h"
    #pragma package(smart_init)
    //---------------------------------------------------------------------------
    // ValidCtrCheck is used to assure that the components created do not have
    // any pure virtual functions.
    //static inline void ValidCtrCheck(TDataComBox *)
    {
            new TDataComBox(NULL);
    }
    //---------------------------------------------------------------------------
    __fastcall TDataComBox::TDataComBox(TComponent* Owner)
            : TComboBox(Owner)
    {
    }
    //---------------------------------------------------------------------------
    TTypeInfo *AnsiStringInfo()   //You know,the macro __typeinfo is only used to obtain typeinfo of vcl not common datatype,so we should use a function to achieve
    {
            TTypeInfo *pTypeInfo=new TTypeInfo;
            pTypeInfo->Name="AnsiString";
            pTypeInfo->Kind=tkString;
            return pTypeInfo;
    }
    //---------------------------------------------------------------------------
    TTypeInfo *IntInfo()
    {
            TTypeInfo *pTypeInfo=new TTypeInfo;
            pTypeInfo->Kind=tkInteger;
            pTypeInfo->Name="int";
            return pTypeInfo;
    }
    //----------------------------The namespace is used by compiler to recoganize control with their name---------------
    namespace Datacombox
    {
            void __fastcall PACKAGE Register()
            {
                     TComponentClass classes[1] = {__classid(TDataComBox)};
                     RegisterComponents("AKing", classes, 0);
                     RegisterPropertyEditor(IntInfo(),__classid(TDataComBox),"BaudRate",__classid(TBaudRateProperty));
                     RegisterPropertyEditor(AnsiStringInfo(),__classid(TDataComBox),"FileName",__classid(TFileNameProperty));
                     RegisterPropertyEditor(AnsiStringInfo(),__classid(TDataComBox),"DataField",__classid(TDataFieldProperty));        }
    }
    //---------------------------------------------------------------------------
    void __fastcall TDataComBox::SetDataSource(TDataSource* DataSource)
    {
            FDataSource=DataSource;
    }
    //-------------------------------------------------------
    void __fastcall TDataComBox::SetDataField(AnsiString Field)
    {
            FDataField=Field;
    }
    //-----------------------------------------------------
    void __fastcall TDataComBox::SetBaudRate(int BaudRate)
    {
            FBaudRate=BaudRate;
    }
    //----------------------------------------------------
    void __fastcall TDataComBox::SetFileName(AnsiString FileName)
    {
            FFileName=FileName;
    }
      

  11.   

    To borlandor:
       看到我发给你的短消息了吗?
       我反复检查了我的代码,但问题依然得不到解决,在object inspector中始终没有DataField属性的下拉列表框。
      

  12.   

    你的类型信息有问题,修改如下:
    TTypeInfo *GetTypeInfo(AnsiString s)
    {
      PPTypeInfo Temp;  Temp = GetPropInfo(__typeinfo(TDataComBox), s)->PropType;  return *Temp;}namespace Datacombox
    {
            void __fastcall PACKAGE Register()
            {
               TComponentClass classes[1] = {__classid(TDataComBox)};
               RegisterComponents("AKing", classes, 0);
               RegisterPropertyEditor(GetTypeInfo("BaudRate") ,__classid(TDataComBox),"BaudRate",__classid(TBaudRateProperty));
               RegisterPropertyEditor(GetTypeInfo("FileName"),__classid(TDataComBox),"FileName",__classid(TFileNameProperty));
               RegisterPropertyEditor(GetTypeInfo("DataField") ,__classid(TDataComBox),"DataField",__classid(TDataFieldProperty));        }
    }
      

  13.   

    另外获取DataSet的Field时,应该使用GetFieldNames,否则在DataSet没有打开时将得不到任何字段名。
    class TDataFieldProperty:public TStringProperty
    {
    public:
       TPropertyAttributes __fastcall GetAttributes()
       {
            return TPropertyAttributes()<<paValueList<<paSortList;
       }
       void __fastcall GetValues(TGetStrProc Proc)
       {
            TStrings *Value;
            TDataSet *pDataSet;
            TDataComBox *pDCBX=dynamic_cast<TDataComBox*>(GetComponent(0));
            if(pDCBX)
            {
                  if(pDCBX->DataSource)
                  {
                    pDataSet=pDCBX->DataSource->DataSet;
                    if(pDataSet)
                    {
                       Value = new TStringList;
                       pDataSet->GetFieldNames(Value);
                       for(int i=0;i<Value->Count;i++)
                       {
                           Proc(Value->Strings[i]);
                       }
                       delete Value;
                    }
                  }
            }
       }
    };
      

  14.   

    To Borlandor:
    你调试通过了吗?
      

  15.   

    因为基于__typeinfo只能识别出vcl类,而不能识别出普通的数据类型,所以只好用:
    TTypeInfo *AnsiStringInfo()
    {
       TTypeInfo *pTypeInfo=new TTypeInfo;
       pTypeInfo->Kind=tkString;
       pTypeInfo->Name="AnsiString";
    }
    我的整型编辑器是可以的----BaudRate属性是有下拉列表框的,莫非字符串必须是你所写的那样。
      

  16.   

    我调试已经通过了,放心用吧!
    C++Builder作组件有点别扭,为什么不用Delphi呢?Delphi只要如此注册即可:
      RegisterPropertyEditor(TypeInfo(String), TYourComponent, 'Field', TFieldsProperty);
      

  17.   

    刚才查了一下:AnsiString的类型类别应该为tkLString//---------------------------------------------------------------------------
    TTypeInfo *AnsiStringInfo()   //You know,the macro __typeinfo is only used to obtain typeinfo of vcl not common datatype,so we should use a function to achieve
    {
            TTypeInfo *pTypeInfo=new TTypeInfo;
            pTypeInfo->Name="AnsiString";
            pTypeInfo->Kind=tkLString;//tkString;
            return pTypeInfo;
    }这样也许就对了,不不过没有试过。
      

  18.   

    对,是我没注意,应该是tkLString,搞了我一整天,谢谢。
    马上给分.