Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   ¿Cómo publicar DBGridColumns? (https://www.clubdelphi.com/foros/showthread.php?t=40536)

DarKraZY 20-02-2007 14:53:13

¿Cómo publicar DBGridColumns?
 
Buenas a todos!

Estoy realizando un componente que sirve para lanzar un formulario de búsqueda. Para simplificar el código voy a poner un ejemplo:

Código Delphi [-]
{ Este formulario además de otras cosas contiene un DBGrid }
TfrmSeleccion = class(TForm)
  dbgDatos: TDBGrid;
end;

{ El componente a utilizar }
TSeleccion = class(TComponent)
private
  FForm: TfrmSeleccion;
public
  constructor Create(AOwner: TComponent); override;
published
  property Columns: TDBGridColumns read FColumns write FColumns stored False;
end;

En el Create del componente hago lo siguiente
Código Delphi [-]
inherited Create(AOwner);

{ Creación del formulario de búsqueda }
FForm := TfrmSeleccion.Create(nil);
FColumns := FForm.dbgDatos.Columns;

Pero esto no funciona, ya que al asignar Fields a las Columns o borrarlas Delphi suelta excepciones.

¿Hay otras formas de hacerlo? ¿O es esta la correcta y estoy haciendo otras cosas mal?

El objetivo del componente es poder configurar las columns en tiempo de diseño. Lo que me interesaría es como poder referenciar o tener acceso desde un componente a la propiedad(TDBGridColumns) de un objeto contenido dentro del componente.

waly2k1 20-02-2007 16:58:08

Qué las hay las hay...
 
Que hay otra forma, seguro hay, y muchas supongo, si bien no es un componente lo mio, hice un form de búsqueda y redefino todas las columnas con la cantidad de campos de una consulta especifica. Mediante Clear, y Add de cada col

Levanto una consulta SQL pasada por parametro, cuando llamo al form, y éste genera nuevamente los campos y asigna la consulta como datasource.
si mal lo recuerdo a cada column de la grid le digo que el datafield := Query.Datafield, errores nada.

Estoy en el trabajo, y acá no existe Delphi, sino te mostraba el ejemplo

Lo único que se me complica es que no puedo pasar un array con los headers de las columnas.

Lepe 20-02-2007 16:58:24

Pero eso te obliga a crear una ventana de Selección para cada búsqueda que tienes que hacer, una para clientes, otra para proveedores.... ¿no sería mejor poder usar la misma ventana para todo tipo de búsquedas?

Así no pierdes tiempo en diseño, además, los datos que tu tienes de prueba en tu programa, seguro que difiere de los datos reales que haya, y por otra parte, al usuario quizás le guste usar otros anchos de columnas.

saludos

waly2k1 21-02-2007 16:26:05

Ejemplo de Form Búsqueda via ADO
 
1 Archivos Adjunto(s)
Adjunto un form de búsqueda, a modo ejemplo creo sirve, igualmente estoy modificándolo todavía, de acuerdo al tipo de campos. Por ej. con fechas genera un error si la fecha tipeada no es una fecha válida.

A todos: Los que puedan mejorarlo, bienvenido sea!!!. Si quieren hacer un componente o lo que fuera, me resultaría muy útil.

En el attach está el form y un .txt la forma de invocarlo.

Saludos

DarKraZY 22-02-2007 19:00:53

Perdón por no haber contestado anteriormente, pero he estado liado con otras cosas y dejado de lado este componente.

Actualmente usamos usamos un único formulario para realizar las búsquedas de todo tipo. Ya que creamos procedimientos almacenados con los mismos parámetros de entrada y de características similares.

Y realizamos una llamada con el array de los campos a visualizar y otro array con los Caption a mostrar.

La idea del componente era englobar todo este proceso. Definir en el componente el stored procedure, y ahora solo me faltaba crear dinámicamente las columns o algún proceso similar.

waly2k1 22-02-2007 20:11:55

Columnas dinámicas
 
Y bueno, lo de las columnas dinámicas lo tenés en el ejemplo.
No te conviene usar directamente un SP en el componente, porque te serviría nada mas para la base de datos en cuestión, que en tu caso creo que es MS-SQL Server, te conviene siempre un string que a su vez puede ser un SP con sus parámetros. por ej: dbo.SP_Clientes_FIND( 'UnCampo', 'OtroCampo' ). Veamos como seguir que la idea está muy buena.

Saludos

DarKraZY 23-02-2007 10:10:18

Hola waly2k1

La verdad es que utilizo Firebird 1.5. Y este es un poco del código del componente para que te hagas una idea:

Código Delphi [-]
  {...}
  published
    property Caption: string read FCaption write SetCaption;
    property CharCase: TEditCharCase read FCharCase write SetCharCase default ecUpperCase;
    property FormColor: TColor read FFormColor write FFormColor default clBtnFace;
    property IBDatabase: TIBDatabase read FIBDatabase write SetIBDatabase;
    property IBTransaction: TIBTransaction read FIBTransaction write SetIBTransaction;
    property ProcedureName: string read FProcedureName write SetProcedureName;
  end;

Como puedes ver ProcedureName es un string pero tengo definida la propiedad de la siguiente manera
Código Delphi [-]
  TStoredProcedureProperty = class(TStringProperty)
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
  end;

{...}

procedure Register;
begin
  RegisterComponents('TabComponente', [TFormSeleccion]);
  RegisterPropertyEditor(TypeInfo(string), TFormSeleccion, 'ProcedureName', TStoredProcedureProperty); {do not localize}
end;

function TStoredProcedureProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paValueList, paSortList];
end;

procedure TStoredProcedureProperty.GetValues(Proc: TGetStrProc);
var
  StoredProc: TIBStoredProc;
  i: Integer;
  NamesList: TStrings;
begin
  StoredProc := TIBStoredProc.Create(nil);
  try
    StoredProc.Database := (GetComponent(0) as TFormSeleccion).IBDatabase;
    StoredProc.Transaction := (GetComponent(0) as TFormSeleccion).IBTransaction;
    NamesList := StoredProc.StoredProcedureNames;
    for I := 0 to NamesList.Count - 1 do
      Proc(NamesList[i]);
  finally
    StoredProc.Free;
  end;
end;

De esta forma en mi componente aparece una lista desplegable con los procedimientos almacenados.

Por cierto, en tu ejemplo no he visto nada de DBGridColumns dinámicas. Porque me gustaría que estuviesen todas las propiedades de una TColumn.

DarKraZY 23-02-2007 11:09:44

Ya lo tengo!

El resultado es el siguiente, y a ver si así lo dejo claro ;) (ya que sé que resultaba lioso).

Tengo un formulario. Dentro de este un DBGrid para mostrar los resultados.

La idea era crear un componente que mostrase ese formulario. Y para que el componente fuese muy útil se me ocurrió tener una propiedad de tipo TDBGridColumns.

Hice muchas pruebas y cuando estaba apunto de crear nuevas clases heredadas de TCollection y TCollectionItem me di cuenta de mi error. En el OnDestroy del componente estaba liberando antes el formulario (que contiene el DBGrid) y después las columns!! He ahí mi error. :)

Y ahora algo de código por si sirve a alguien:

Código Delphi [-]
TFormSeleccion = class(TComponent)
  private
    FForm: TfrmSeleccion;
    FColumns: TDBGridColumns;
    procedure SetColumns(const Value: TDBGridColumns);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Columns: TDBGridColumns read FColumns write SetColumns;
  end;

constructor TFormSeleccion.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  { Creación del formulario de búsqueda }
  FForm := TfrmSeleccion.Create(nil);

  FColumns := TDBGridColumns.Create(FForm.dbgSeleccion, TColumn);
end;

destructor TFormSeleccion.Destroy;
begin
  FColumns.Free;

  FForm.Close;
  FForm.Free;
  
  inherited;
end;

procedure TFormSeleccion.SetColumns(const Value: TDBGridColumns);
begin
  FColumns.Assign(Value);
end;

NOTA: No pongo todo el código para no liar más la cosa, jeje.

DarKraZY 23-02-2007 12:02:49

Mi gozo en un pozo :( (expresión utilizada después de una alegría, llega una decepción)

Todo el código anterior sigue fallando. Cuando se elimina una Column del Collection salta error de memoria.

Investigando más a fondo la VCL parece ser que TDBGridColumns tiene como Owner al DBGrid (como debe de ser). Y buscando en la unit Classes he encontrado la solución ¡TOwnedCollection!. Que es un descendiente de TCollection pero con Owner explícito en el Create.


Manos a la obra y funcionando (por ahora jeje)
Código Delphi [-]
  TOwnedDBGridColumns = class(TDBGridColumns)
  private
    FOwner: TPersistent;
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TPersistent; Grid: TCustomDBGrid;
      ColumnClass: TColumnClass);
  end;

constructor TOwnedDBGridColumns.Create(AOwner: TPersistent;
  Grid: TCustomDBGrid; ColumnClass: TColumnClass);
begin
  inherited Create(Grid, ColumnClass);
  FOwner := AOwner;
end;

function TOwnedDBGridColumns.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

waly2k1 23-02-2007 18:13:48

Código muy avanzado...
 
En realidad pensé que lo que necesitabas era armar las columnas en un DBGrid en forma dinámica (campos, titulos, etc.), eso está en el ej. que publiqué. El resto entiendo poco y nada, estoy muy verde en Delphi.

Después presto más atención a tu código, pero no entiendo bien para que creas vos una colección TColumn ???

Saludos


La franja horaria es GMT +2. Ahora son las 14:53:06.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi