PDA

Ver la Versión Completa : Problemas de Inicialización de un componente


Angel
16-07-2003, 11:13:18
Hola a todos,

Os explico muy por encima lo que quiero hacer, tengo un componente, del cual he creado un TCollection para poder especificar ciertos valores de los campos de una tabla, y resulta que cuando creo el componente, quiero que se me inicialice esa colection con los campos que hay en una tabla. Me parece que no me explico, a ver si con un poco de código lo consigo explicar:


{ TFieldItem }
TFieldItem = class(TCollectionItem)
private
FName: String;
FColTitle: String;
FDefaultSearch: Boolean;
FSize: Integer;
protected
function GetDisplayName: String; Override;
public
procedure Assign(Source: TPersistent);
procedure SetDefaultSearch (Value: Boolean);Virtual;
published
property Name: String read FName write FName;
property ColTitle: String read FColTitle write FColTitle;
property DefaultSearch:Boolean read FDefaultSearch write SetDefaultSearch;
property Size: Integer read FSize write FSize;
end;

{ TFieldList }
TFieldList = class(TCollection)
private
FOwner: TPersistent;
function GetItem(Index: Integer): TFieldItem;
procedure SetItem(Index: Integer; Value: TFieldItem);
protected
public
function GetOwner: TPersistent; Override;
constructor Create(AOwner: TPersistent);
destructor Destroy; override;
procedure Add(AName: String; ADefaultSearch:Boolean; AColTitle: String;
ASize: Integer);
procedure Clear;
property Items[Index: Integer]: TFieldItem read GetItem write SetItem; default;
published
end;

TDBViewer = class(TComponent)
private
FDataSet: TDataSet;
FReturnParams: Integer;
FReturnValues: array of Variant;
FFieldDefs: TFieldList;
FFormTitle : String;
FFormWidth: Integer;
FFormHeight:Integer;
FEditColor: TColor;
FGridColor: TColor;
FDataLink: TFieldDataLink;
function GetDataField: string;
function GetDataSource: TDataSource;

procedure SetDataField(const Value: string);
procedure SetDataSource(Value: TDataSource);

public
procedure SetDataSet(Value: TDataSet); virtual;
procedure SetReturnParams(Value: Integer); virtual;
function GetDataSet: TDataSet; virtual;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure Execute;
function ReturnParamValues (Param:Integer):Variant;

published
property FieldDefs: TFieldList read FFieldDefs;
property DataSet: TDataSet read GetDataSet write SetDataSet;
property ReturnParams: Integer read FReturnParams Write SetReturnParams default 1;


property FormTitle: String read FFormTitle Write FFormTitle;
property FormHeight: Integer read FFormHeight Write FFormHeight;
property FormWidth: Integer read FFormWidth Write FFormWidth;
property EditColor: TColor read FEditColor Write FEditColor;
property GridColor: TColor read FGridColor write FGridColor;

end;


Pues bien, lo que quiero es que cuando se cree un DBViewer la propiedad FFieldDefs contenga las columnas que hay dentro del DataSet (eso en tiempo de diseño), pero que cuando se ejecute la aplicación, yo pueda acceder a esos items (y a sus valores, tanto si se han cambiando como si no).

Espero haberme explicado, y gracias a todos

delphi.com.ar
16-07-2003, 16:16:00
Lo que tu quieres es hacer como un DBGrid, que si no definimos ninguna columna estas se cargan dinámicamente?
Bueno, puedes husmear el código del DBGrid, si no te sirve te puedo hacer un comentario de como lo hago en los componentes "Export Suite".

Saludos!

andres1569
16-07-2003, 16:16:10
Hola:

Creo que lo más apropiado es que la creación de esos Items la realices en el método SetDataSet de TDBViewer, así se inicializan cada vez que el programador/usuario cambia el DataSet, ya sea en diseño o en ejecución (al crearse el TDBViewer no puede ser porque aún no sabemos cuál es el DataSet). Para evitar que se sobreescriban los valores cuando se lea del archivo .DFM, haces la comprobación de la variable State:

procedure TDBViewer.SetDataSet (Value: TDataSet);
begin
if Value <> FDataSet then
begin
FDataSet := Value;
if NOT (dsReading in ComponentState) then
begin
FFieldDefs.Clear;
// aquí rellenas los Items tomados del DataSet
end;
if Value <> nil then Value.FreeNotification;
end;
end;

Angel
17-07-2003, 16:58:14
Gracias a todos, sois unas "máquinas"... La verdad es que lo terminé solucionando de una forma muy parecida a la que expuso andrés, sin embargo, ahora me encuentro con otro "problema" y es que me gustaría saber como acceder a las propiedades de la colección utilizando el botón derecho de ratón sobre el componente. Os debe decir en primer lugar que consigo crear los menús, pero no sé que poner dentro la función para mostar la misma ventana que aparece cuando pulso el botón con los tres puntos (...). El día que lo termine propondré el dejarlo para dominio público, y que alguien intente mejorarlo (quizás yo lo haya hecho un poco mal, pero es mi primer componente).

De nuevo gracias a todos........ ¡¡¡¡ Máquinas !!!!

andres1569
18-07-2003, 08:29:41
Hola:

En la unit colnedit.pas que encontrarás en ...DelphiX\Source\Property Editors\ está la función ShowCollectionEditor, que es la que debes llamar desde el editor de tu componente (método ExecuteVerb) para que te muestre la colección.

Esto a partir de Delphi 5. Si alguien sabe cómo conseguirlo con la versión 4, le estaré agradecido. En los fuentes no viene esa unit, y no sé dónde carajos puede estar la función que hace eso mismo.

Saludos

Angel
18-07-2003, 09:25:42
En la unit colnedit.pas que encontrarás en ...DelphiX\Source\Property Editors\ está la función ShowCollectionEditor, que es la que debes llamar desde el editor de tu componente (método ExecuteVerb) para que te muestre la colección.


No funciona, al intentarse compilar la unidad colnedit busca otra unit (la "ToolWnds") que no está por ninguna parte. A propósito, tengo Delphi 5.

delphi.com.ar
18-07-2003, 15:52:20
Recomendación: Arma un paquete de diseño y otro de ejecución. http://www.clubdelphi.com/foros/showthread.php?s=&threadid=1053

andres1569
18-07-2003, 16:59:19
Hola Angel:

En efecto, falta esa unit que dices, ToolWnds; hace tiempo que me peleé con ese tema y lo dí por perdido, lo quería para unos componentes en Delphi 4.0, y ví que en Delphi 5 existía esa función que te dije, pero no la había probado.

Supongo que lo que dice Delphi.Com.Ar te servirá (suele acertar :D :D ). Como es una característica que te hace falta para el diseño, y Delphi usa paquetes en el IDE, supongo que se tratará de incluir el package correspondiente, aunque me queda la duda de cómo llamarlo desde tu editor de propiedades.

Si lo llegas a hacer funcionar, por favor pon un post indicando los pasos seguidos.

Saludos ¡MÁQUINAS!

delphi.com.ar
18-07-2003, 17:09:00
Te garantizo que funciona, lo puedes probar bajando los mis componentes "Export Suite" de mi página que hacen lo que tu pides.


PD: :D

Angel
21-07-2003, 09:43:30
Ahora si que me habeis perdido :confused: .

No, en serio, he conseguido montar los dos paquetes (aunque seguramente lo habré hecho mal :D ).

Vayamos por partes:
He creado un paquete de diseño llamado DsgDBViewPkg que contiene tres ficheros, DBView.dcr, DBView.pas y DBViewReg.pas (este último es el que contiene las lineas de registro del componente y el editor, algo parecido a esto: )



interface

procedure Register;

implementation

uses
Classes,
{$IFDEF VER130}DsgnIntf{$ELSE}DesignIntf, DesignEditors{$ENDIF},
FiltEdit, DBView;


procedure Register;
begin
RegisterComponents('DBViewer', [TDBViewer]);
RegisterComponentEditor (TDBViewer,TFieldDefsProperty)
end;

end.


Todo compila, todo se instala, pero sigo sin saber como llamar al editor, ya que con ShowCollectionEditor no funciona (seguirá faltandome algo)

Sin embargo, estoy convencido que la forma en que tengo montados los paquetes esta mal, puesto que en el paquete RunDBViewPkg únicamente tengo el fichero DBView.dcr.

Como os he comentado estoy algo "perdido", y me parece que para ser mi primer componente me he pasado (a lo mejor debería haber empezado por uno más fácil, pero es el que necesito en el trabajo para hacerme la faena más cómoda)

De verdad que me sabe muy mal "molestaros", pero es que no sé por donde continuar.


Muchas gracias a todos.

delphi.com.ar
21-07-2003, 16:27:17
Primero te quisiera comentar que a mi parecer, y suponiendo lo que contiene cada archivo, el archivo DBView.pas no tendría que pertenecer al paquete de DesignTime, solamente al de RunTime.
Con respecto a tu problema, me gustaría que nos muestres el código del TFieldDefsProperty, que seguramente ahí esta el problema.

Angel
22-07-2003, 12:30:34
La verdad es que no tengo ningún problema en mostraros todo el código, es más a continuación os muestro el que me habeis solicitado. Por otra parte, con lo que me comentas de no poner del Fichero DBView en el modulo de Diseño, resulta, que si no, no me deja continuar.....

Pero bueno, vamos a mostrar algo de código :D

en el fichero DBView.pas tengo esto:


{ TFieldItem }
TFieldItem = class(TCollectionItem)
private
FName: String;
FColTitle: String;
FDefaultSearch: Boolean;
FSize: Integer;
protected
function GetDisplayName: String; Override;
public
procedure Assign(Source: TPersistent);
procedure SetDefaultSearch (Value: Boolean);Virtual;
procedure Edit;
published
property Name: String read FName write FName;
property ColTitle: String read FColTitle write FColTitle;
property DefaultSearch:Boolean read FDefaultSearch write SetDefaultSearch;
property Size: Integer read FSize write FSize;
end;

{ TFieldList }
TFieldList = class(TCollection)
private
FOwner: TPersistent;
protected
public
function GetOwner: TPersistent; Override;
procedure Edit;
constructor Create(AOwner: TPersistent);
destructor Destroy; override;
procedure Add(AName: String; ADefaultSearch:Boolean; AColTitle: String;
ASize: Integer);
procedure Clear;
function GetItem(Index: Integer): TFieldItem;
procedure SetItem(Index: Integer; Value: TFieldItem);
property Items[Index: Integer]: TFieldItem read GetItem write SetItem; default;
published
end;

TDBViewer = class(TComponent)
private
FDataSet: TDataSet;
FReturnParams: Integer;
FReturnValues: array of Variant;
FFieldDefs: TFieldList;
FFormTitle : String;
FFormWidth: Integer;
FFormHeight:Integer;
FEditColor: TColor;
FGridColor: TColor;
FDataLink: TFieldDataLink;
function GetDataField: string;
function GetDataSource: TDataSource;

procedure SetDataField(const Value: string);
procedure SetDataSource(Value: TDataSource);

public
procedure Assign(Source: TPersistent);
procedure SetDataSet(Value: TDataSet); virtual;
procedure SetReturnParams(Value: Integer); virtual;
function GetDataSet: TDataSet; virtual;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure Execute;
function ReturnParamValues (Param:Integer):Variant;
procedure Edit;

published
property FieldDefs: TFieldList read FFieldDefs write FFieldDefs;
property DataSet: TDataSet read GetDataSet write SetDataSet;
property ReturnParams: Integer read FReturnParams Write SetReturnParams default 1;
property FormTitle: String read FFormTitle Write FFormTitle;
property FormHeight: Integer read FFormHeight Write FFormHeight;
property FormWidth: Integer read FFormWidth Write FFormWidth;
property EditColor: TColor read FEditColor Write FEditColor;
property GridColor: TColor read FGridColor write FGridColor;
end;

TFieldDefsProperty = class (TComponentEditor)
private
procedure executeVerb (index:Integer);Override;
function GetVerb (Index:Integer):String;override;
function GetVerbCount:Integer; Override;
end;




esto está en el DBViewReg.pas



unit DBViewReg;

interface

procedure Register;

implementation

uses
Classes,
{$IFDEF VER130}DsgnIntf{$ELSE}DesignIntf, DesignEditors{$ENDIF},
FiltEdit, DBView;


procedure Register;
begin
RegisterComponents('DBViewer', [TDBViewer]);
RegisterComponentEditor (TDBViewer,TFieldDefsProperty)
end;

end.



y por último, esto es lo que tengo en el frmView.pas



type
TfrmVisor = class(TForm)
dsDataSource: TDataSource;
dbGrid: TDBGrid;
pTop: TPanel;
gbBuscar: TGroupBox;
cbFields: TComboBox;
eSearch: TEdit;
procedure FillcbFields;
procedure Inicializar;
procedure dbGridColEnter(Sender: TObject);



procedure FormShow(Sender: TObject);
procedure dbGridDblClick(Sender: TObject);
procedure eSearchChange(Sender: TObject);
procedure FormKeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
public
FDataSet: TDataSet;
FReturnParams: Integer;
FReturnValues: array of Variant;
FColTitles: TStringList;
FDefaultSearch: TFieldItem;
FFieldDefs: TFieldList;
end;


var
frmVisor: TfrmVisor;

delphi.com.ar
22-07-2003, 16:00:30
Exactamente lo que me interesa es la implementación de la clase TFieldDefsProperty.

Saludos!

Angel
23-07-2003, 08:49:31
Perdón, pero no entendí tu petición, sin embargo no creo que te sirva de mucho, pero aqui te la dejo escrita:


procedure TFieldDefsProperty.executeVerb (index:Integer);
begin
if index=0 then //Esta primera opción sería para poder editar los campos
begin
end;

if index=1 then //Esta segunda opción muestra una vista preliminar de los resultados.
begin
TDBViewer(component).Execute;
end;
end;

function TFieldDefsProperty.GetVerb (Index:Integer):String;
begin
if index=0 then
result:='Edit Fields';
if index=1 then
result := 'Execute';
end;

function TFieldDefsProperty.GetVerbCount:Integer;
begin
result:=2;
end;

delphi.com.ar
23-07-2003, 17:05:50
Bueno, veo que te falta lo mas importante, llamar al procedimiento ShowCollectionEditor en el método ExecuteVerb cuando Index = 0 ('Edit Fields'). ¡¡Te has olvidado lo que te dijo Andrés!!


Saludos!

Angel
24-07-2003, 08:53:01
Uffffff !!! :D

Conseguido !!!!!

Tal como comentabas en tu última respuesta, me faltaba por incluir la linea del ShowCollectionEditor y efectívamente, despues de pelearme un poco con los parámetros (3 minutos más o menos) he obtenido el resultado deseado.

Por si a alguien le puede interesar, la linea que he incluido ha sido la siguiente:


procedure TFieldDefsProperty.executeVerb (index:Integer);
begin
if index=0 then
begin
// Esta es la maldita línea que faltaba.
showcollectionEditor(self.Designer,Component,TDBViewer(component).FieldDefs,'FieldDefs');
end;

if index=1 then
begin
TDBViewer(component).Execute;
end;
end;




Así pues, gracias a todos por vuestra inestimable ayuda, si algún día publico el componente os haré mención especial.

Supongo que con esto podemos dejar el hilo cerrado, en espera de que pueda servirle a alguien, al menos tanto como a mí. De nuevo, otra vez gracias.



Saludos

delphi.com.ar
24-07-2003, 15:32:40
¿Vistes que es más interesante investigarlo que te den la respuesta?.... Y ahora: ¿No te interesa que al hacer doble click sobre tu componente se abra el editor CollectionEditor?....
Te dejo que lo investigues, si se te complica, te doy la respuesta! :D

Saludos...