动态生成控件,但是类要根据条件才能知道,如何解决?(高分)(100分)

  • 主题发起人 主题发起人 轻音乐
  • 开始时间 开始时间
这个不难的,事实上这种做法很普遍.如有些控件在动态生成内置线程或对象前会
提供一个事件让程序来改变缺省的线程或对象类.
TClass.Create就可以了,最多再强制一下比如
FDClass:TClass;
TFieldClass(FdClass).Create(DataSet1);

至于设置属性可以用RTTI来实现,只要属性名知道就可以.
不同的类有不同的属性,可以用TObject.ClassName()取出对象的类名
再用typinfo.SetPropValue根据对象的属性名(String)设置对象的属性值





 
谁有更好的方法!!
 
to savenight 大侠你能用bde的table和AdoTable写个例子吗?
它俩公共基类都是TDataSet,但是又如何table继承TTable,AdoTable继承TAdoTable呢?
我只要求这两个Table控件都叫统一的名称,并且table有TTable的属性,
AdoTable有TAdoTable的属性。
 
>>lynu:
TClass.Create就可以了,最多再强制一下比如
FDClass:TClass;
TFieldClass(FdClass).Create(DataSet1);

这个我不怎么明白,能解释一下TClass的用法和作用吗???
感觉你的作法更通用些。。。
 
看来,楼上的那位是利用了类引用。
把控件的classtype当成一个变量,赋给一个类变量。
然后再根据这个类变量来create。
这样,就可以达到产生不同控件的目的。
 
这样行吗:
设计时定义一个Ttable对象和一个ToraTable对象放到窗体上,比方Atable,Aoratable;
他们的Name属性是Atable,和Aoratable
运行时想要创建Table或Oratable是将这样
procedure xxx()
var tmptable1 :ttable;
tmptable2 :toratable;
begin
Atable.free;
Aoratable.free;
if 条件 then
begin
tmptable1 : = ttable.create(self);
tmptable1.name := atable;
end
else
begin
tmptable2 := toratablecreate(self);
tmptable2.name := aoratable;
end;
end;
调用时
if Assigned(atable) then
DataSource1.DataSet:=atable
else if assigned(aoratable) then
datasoorce1.dataset := aoratable;
可以吗,这样编译器可以认
 
>>它俩公共基类都是TDataSet,但是又如何table继承TTable,AdoTable继承TAdoTable呢?
>>我只要求这两个Table控件都叫统一的名称,并且table有TTable的属性,
>>AdoTable有TAdoTable的属性。

如果要严格达到这种效果,就只能使用RTTI了。但按名访问效率很低而且是官方不推荐做
法(参考DELPHI开发人员指南)。而且这样做意义不大,除了一些公共属性和方法外,其他
的属性和方法(例如TTable中有,AdoTable中没有,反之亦然)在使用之前还是要作类型
检查,否则就会出异常。

假定你的TOraTable是由TDataSet派生出来的。(如果不是,合并TTable和TOraTable的操作
意义不大,TOraTable甚至不能赋值给TDataSource。)

我觉得这个问题的解决方法是,首先把你程序里的业务规则和数据库处理尽量分离。然后定
义一个数据库处理的基类TDataGateway,它“代理”一个TDateSet对象。在基类中可以包含一些在DateSet
层面上的操作(其实包括了大部分的数据库操作了,FieldByName, First, Next等操作都是
TDataSet的)。然后在这个从基类派生两个子类:TTableDW和TOraTableDW,在这两个子类中
加入TTable或TOraTable层面上的操作(使用强制类型转换)。当然,为了使数据能被TDataSource
使用,TDataGateway(基类)中应该有一个属性返回它“代理”的TDAteSet对象。这样就可以在
业务模块里根据不同需要使用不同DataGateway来操作不同的数据库了。
 
补充几点,
1)在子类中定义的TTable和TOraTable相关操作,在基类应该有相应的虚方法,否则又会出现“未定义标识符”的问题了。
2)在业务部分,可以统一使用基类对象。只要在构造时使用不同子类的构造函数就可以了。
 
这群菜用RTTI。
 
范例程序如下:
Form中有一TTable控件Table1,一TAdoTable控件AdoTable1。使用这两个控件仅仅为了
方便设置数据库连接,在设计期把Table1.DatabaseName, Table.TableName,
TAdoTable.connectionstring与TAdoTable.Table设好。
另外,有一个Datasource1和DBGrid1用于显示数据。

超类定义为:

TGatewayType = (gwTable, gwAdoTable);

TDataGateway = class

private
_Table : TDataSet;
function GetActive: Boolean;
procedure SetActive(const Value: Boolean);
function GetDataSet: TDataSet;

public
property DataSet:TDataSet read GetDataSet;
//TDataSet 中的方法 (仅保留常用的,其他复杂方法可限制在本类内使用,
//本类仅提供业务接口)
procedure Append;
procedure AppendRecord(const Values: array of const);
procedure Cancel;
procedure Close;
procedure Delete;
procedure Edit;
procedure EnableControls;
function FieldByName(const FieldName: string): TField;
procedure First;
procedure Insert;
procedure InsertRecord(const Values: array of const);
function IsEmpty: Boolean;
procedure Last;
procedure Next;
procedure Open;
procedure Post;
procedure Refresh;
function Bof: Boolean;
function Eof: Boolean;
property Active: Boolean read GetActive write SetActive;
//业务方法

//子类虚方法
procedure SetDatabase(DatabaseIdentifier:string); virtual; abstract;
procedure SetTable(TableIdentifier:string); virtual; abstract;
end;

其中(仅举例,其他类似)
procedure TDataGateway.Append;
begin
_Table.Append;
end;

procedure TDataGateway.AppendRecord(const Values: array of const);
begin
_Table.AppendRecord(Values);
end;

function TDataGateway.Bof: Boolean;
begin
Result := _Table.Bof;
end;

TTable子类:
定义:
TTableGW = class(TDataGateway)
public
constructor Create; overload;
destructor Destory; overload;
procedure SetDatabase(DatabaseIdentifier:string); override;
procedure SetTable(TableIdentifier:string); override;
end;
实施:
constructor TTableGW.Create;
begin
inherited;
_Table := TTable.Create(Application);
end;

destructor TTableGW.Destory;
begin
FreeAndNil(_Table);
inherited;
end;

procedure TTableGW.SetDatabase(DatabaseIdentifier: string);
begin
(_Table as TTable).DatabaseName := DatabaseIdentifier;
end;

procedure TTableGW.SetTable(TableIdentifier: string);
begin
(_Table as TTable).TableName := TableIdentifier;
end;

AdoTable子类:
定义:
TAdoTableGW = class(TDataGateway)
public
constructor Create; overload;
destructor Destory; overload;
procedure SetDatabase(DatabaseIdentifier:string); override;
procedure SetTable(TableIdentifier:string); override;
end;
实施:
constructor TAdoTableGW.Create;
begin
inherited;
_Table := TADOTable.Create(Application);
end;

destructor TAdoTableGW.Destory;
begin
FreeAndNil(_Table);
inherited;
end;

procedure TAdoTableGW.SetDatabase(DatabaseIdentifier: string);
begin
(_Table as TADOTable).ConnectionString := DatabaseIdentifier;
end;

procedure TAdoTableGW.SetTable(TableIdentifier: string);
begin
(_Table as TADOTable).TableName := TableIdentifier;
end;

于是,在使用时:
procedure TForm1.FormCreate(Sender: TObject);
begin
TableGW := TADOTableGW.Create;
//若是用BDE表,则 TableGW := TTableGW.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//变动数据源类型时,数据操作代码不用修改。但到数据库的连接因为Ado使用连接字,
//BDE使用数据库名,因此这个差别是必须注意的。
TableGW.SetDatabase(self.ADOTable1.ConnectionString);
TableGW.SetTable(self.ADOTable1.TableName);
//BDE表时:
//TableGW.SetDatabase(self.Table1.DatabaseName);
//TableGW.SetTable(self.Table1.TableName);
//以下的数据库操作不用改变。
self.DataSource1.DataSet := TableGW.DataSet;
TableGW.Active := true;//在DBGrid中显示数据表内容。
end;
 
用类引用不是很简单吗
type
TMyClass=class of TDataset;
...
var
Form1: TForm1;
BDE_Table: TMyClass;
MyTable: Tdataset;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
BDE_Table:= TTable;
MyTable:= BDE_Table.Create(self);
MyTable.DatabaseName:='c:/db';
end;
 
我没看过各位大侠的代码。
我想这样不知道行不行的。我没有Delphi了现在。
Type TDBClass=class of TDataSet;

Procedure Form1.MyCreateDataSet(DBClass:TDBClass);
begin
with DBClass.Create(Self) do
begin
DataSource:='';
DataSet:=...;//自己设
end;
end;

调用
MyCreateDataSet(TTable);
MyCreateDataSet(TADOTable);
 
错咯
另起一个单元
TBDETable= TTable;
TOracleTable= TOraTable;//toratable是从ttable继承出来的。重要!
...
initialization
registerclass(TBDETable);
registerclass(TOraTable);
使用方法
Table:= TTable(FindClass('T'+DBName+'Table')).Create(Self) //其中DBName就是BDE或Oracle
 
学习中..............................
 
后退
顶部