Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 25-07-2003
HombreSigma HombreSigma is offline
Miembro
 
Registrado: jun 2003
Ubicación: World
Posts: 114
Poder: 21
HombreSigma Va por buen camino
Error en Componente TDBGridPlus

Tengo un componente propio llamado TDBGridPlus descendiente de TDBGrid como se muestra en el código siguiente:

unit DBGridPlus;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, DBGrids, DB;

type
TDBGridPlus = class(TDBGrid)
private
procedure MiDrawDataCell
(Sender: TObject; const Rect: TRect;
Field: TField; State: TGridDrawState);
public
{ Public declarations }
property InplaceEditor;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;

implementation

constructor TDBGridPlus.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Self.OnDrawDataCell:=MiDrawDataCell;
end;

procedure TDBGridPlus.MiDrawDataCell
(Sender: TObject; const Rect: TRect;
Field: TField; State: TGridDrawState);
var
Grid : TStringGrid;
Texto : String;
Rectangulo : TRect;
begin
Rectangulo:=Rect;
Grid := TStringGrid(Sender);
if Field.IsBlob
then begin
Grid.Canvas.FillRect(Rect);
Texto := Field.AsString;
DrawText( Grid.Canvas.Handle,
PChar(Texto),
StrLen(PChar(Texto)),
Rectangulo,
DT_WORDBREAK);
end;
end;

destructor TDBGridPlus.Destroy;
begin
inherited Destroy;
end;


end.

Como se ve trato de llamar cierto código nuevo dentro del evento OnDrawDataCell.

Pero no me funciona. No me interesa que el nuevo código funcione (que en este caso muestra un campo memo cualquiera y funciona) sino que se active cuando use el evento OnDrawDataCell. Pero ni siquiera se ejecuta.

Alguna sugerencia ?

Gracias por la información.
__________________
SigmaMan
Responder Con Cita
  #2  
Antiguo 26-07-2003
Avatar de marto
marto marto is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona, Catalunya
Posts: 882
Poder: 22
marto Va por buen camino
Hola,

No estoy seguro, pero se me ocurre que si creas el componente en diseño, el puntero al evento deje de apuntar a tu función, ya que normalmente todos aparecen apuntando a Nil.
De todas maneras, en todos los componentes que he creado a partir de otros de la VCL, donde he tenido que hacer cosas parecidas a la que tú haces he usado otra técnica que me parece mejor.
Te cuento, normalmente, para cada evento de un componente existe un procedimiento protected y virtual que es el que se encarga de llamar al evento si este esta asignado. Borland decidió hacer esto así pensando en que si alguien quería heredar de un componente pudiese modificar el comportamiento ante cierto evento sin tener que usar directamente el propio puntero. Además, esto es peligroso, ya que si se instancia el nuevo componente y se quiere programar dicho evento, perderás la funcionalidad que habías añadido al heredar. No sé si me he explicado, pero me permito modificar tu código como ejemplo.
De todas formas, ten en cuenta que no tengo el Delphi a mano y no estoy seguro que el procedimiento que voy a sobreescribir exista o se llame así, pero como ejemplo creo que servirá.

Código:
unit DBGridPlus;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, DBGrids, DB;

type
TDBGridPlus = class(TDBGrid)
private
  procedure MiDrawDataCell(Sender: TObject; const Rect: TRect;Field: TField; State: TGridDrawState);
protected
  procedure DoDrawDataCell(const Rect: TRect;Field: TField; State: TGridDrawState);override;
//este es el procedimiento que llama al evento, comprueba que es así

public
{ Public declarations }
property InplaceEditor;
//me he cargado el constructor y destructor porque no hacian falta
end;

implementation

procedure TDBGridPlus.DoDrawDataCell(const Rect: TRect;Field: TField; State: TGridDrawState);
begin
  MiDrawDataCell(Self, Rect, Field, State);
  inherited DoDrawDataCell(Rect, Field, State);
{

llamar antes o despues al inherited depende si quieres que se ejecute antes tu código o el de el evento.
Piensa que el codigo de este procedure será algo asi:
  procedure TDBGrid.DoDrawDataCell(const Rect: TRect;Field: TField; State: TGridDrawState);
  begin
    if Assigned(FOnDrawDataCell) then
       FOnDrawDataCell(Rect, Field, State);
  end;

}
end;

procedure TDBGridPlus.MiDrawDataCell(Sender: TObject; const ect: TRect; Field: TField; State: TGridDrawState);
var
  Grid : TStringGrid;
  Texto : String;
  Rectangulo : TRect;
begin
  Rectangulo:=Rect;
  Grid := TStringGrid(Sender);
  if Field.IsBlob
  then begin
    Grid.Canvas.FillRect(Rect);
    Texto := Field.AsString;
    DrawText( Grid.Canvas.Handle,
    PChar(Texto),
   StrLen(PChar(Texto)), Rectangulo, DT_WORDBREAK);
end;
end;



end.
__________________
E pur si muove
Responder Con Cita
  #3  
Antiguo 26-07-2003
HombreSigma HombreSigma is offline
Miembro
 
Registrado: jun 2003
Ubicación: World
Posts: 114
Poder: 21
HombreSigma Va por buen camino
Gracias por tu sugerencia.

Sin embargo, la nueva versión tampoco funciona:

unit DBGridPlus;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, DBGrids, DB;

type
TDBGridPlus = class(TDBGrid)
private
protected
procedure DefaultDrawColumnCell
(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
public
{ Public declarations }
property InplaceEditor;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure MiDefaultDrawColumnCell
(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
end;

implementation

uses DBTables;

constructor TDBGridPlus.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;

destructor TDBGridPlus.Destroy;
begin
inherited Destroy;
end;

procedure TDBGridPlus.MiDefaultDrawColumnCell(const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
P:array [0..50] of char;
BS:tBlobStream;
S:String;
begin
if Column.Field is TMemoField then begin
with Self.Canvas do begin
BS:=tBlobStream.Create(TMemoField(Column.Field), bmRead);
FillChar(P,SizeOf(P),#0); {termina la cadena nula}
BS.Read(P, 50); {Lee 50 caracteres del memo dentro del blobStream}
BS.Free;
S:=StrPas(P);
while Pos(#13, S) > 0 do {remueve caracteres retornos de carro y nueva linea}
S[Pos(#13, S)]:=' '; {Retorno de carro}
while Pos(#10, S) > 0 do
S[Pos(#10, S)]:=' '; {Nueva linea}
FillRect(Rect); {Limpia la celda}
TextOut(Rect.Left, Rect.Top, S); {Llena celda con dato memo}
end;
end;
end;

procedure TDBGridPlus.DefaultDrawColumnCell(const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
MiDefaultDrawColumnCell
(Rect, DataCol, Column, State);
inherited DefaultDrawColumnCell
(Rect, DataCol, Column, State);
//if Assigned(FOnDrawDataCell) then
// FOnDrawDataCell(Rect, Field, State);
end;

end.


Notarás que cambie el método a 'DefaultDrawColumnCell' porque Delphi 7 sugiere que trabaje con este, pues el otro es obsoleto.

El código que pretendo ejecutar escribe un memo en una rejilla. Este algoritmo funciona si lo coloco en el evento OnDrawColumCell del TDBGrid del formulario. Mi idea es que este pueda ejecutarse siempre que use TDBGridPlus que es heredado de TDBGrid. Pero ni siquiero logro que se ejecute !!

Deje el construct y el destructor por si acaso los necesito, en otra versión modificada del código.

DE nuevo acepto sugerencias.

Gracias de antemano
__________________
SigmaMan
Responder Con Cita
  #4  
Antiguo 27-07-2003
andres1569 andres1569 is offline
Miembro
 
Registrado: may 2003
Posts: 908
Poder: 22
andres1569 Va por buen camino
Hola:

Creo que deberías redefinir el método DrawColumnCell que es dynamic (virtual), y no DefaultDrawColumnCell, este método es estático y parece estar pensado para llamarlo desde nuestro código si queremos conseguir el funcionamiento por defecto y así evitarnos trabajo extra.

En realidad, a partir de Delphi 4.0, están obsoletos los métodos DrawDataCell y DefaultDrawDataCell, y se deben emplear DrawColumnCell y DefaultDrawColumnCell (cambia lo de Data por Column), pero ten en cuenta lo que te he dicho anteriormente, el método DefaultDrawColumnCell no se debe sobreescribir (en tu caso lo que has hecho ha sido definir uno nuevo con el mismo nombre, no te habrá dejado ponerle override porque es estático). El método que interesa es DrawColumnCell.

La cosa quedaría así:
Código:
type

TDBGridPlus = class(TDBGrid)
protected
  procedure DrawColumnCell (const Rect: TRect; DataCol: Integer; 
    Column: TColumn; State: TGridDrawState);  override;
  public
    // el procedure MiDefaultDrawColumnCell ahora sobra
end;

...

procedure TDBGridPlus.DrawColumnCell(const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  // aquí pones el código que antes se hacía en MiDefaultDrawColumnCell
  // y te evitas ese método, puesto que reciben los mismos parámetros
  inherited DrawColumnCell;
end;
Como muy bien te explicó Marto, dependiendo de lo quieras lograr, colocarás antes o después la llamada a inherited DrawColumnCell;
__________________
Guía de Estilo

Última edición por andres1569 fecha: 27-07-2003 a las 08:21:14.
Responder Con Cita
  #5  
Antiguo 27-07-2003
HombreSigma HombreSigma is offline
Miembro
 
Registrado: jun 2003
Ubicación: World
Posts: 114
Poder: 21
HombreSigma Va por buen camino
Gracias por las anotaciones, ambas sirvieron.

He aquí el componente TDBGridplus que permite visualizar (aunque no modificar, pero este codigo es mucho más facil de agregar) campos memo, por si a alguien de foro le interesa.

unit DBGridPlus;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, DBGrids, DB;

type
TDBGridPlus = class(TDBGrid)
private
protected
procedure DrawColumnCell
(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);override;
public
{ Public declarations }
property InplaceEditor;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;

implementation

uses DBTables;

constructor TDBGridPlus.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;

destructor TDBGridPlus.Destroy;
begin
inherited Destroy;
end;

procedure TDBGridPlus.DrawColumnCell(const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
P:array [0..50] of char;
BS:tBlobStream;
S:String;
begin
if Column.Field is TMemoField then begin
with Self.Canvas do begin
BS:=tBlobStream.Create(TMemoField(Column.Field), bmRead);
FillChar(P,SizeOf(P),#0); {termina la cadena nula}
BS.Read(P, 50); {Lee 50 caracteres del memo dentro del blobStream}
BS.Free;
S:=StrPas(P);
while Pos(#13, S) > 0 do {remueve caracteres retornos de carro y nueva linea}
S[Pos(#13, S)]:=' '; {Retorno de carro}
while Pos(#10, S) > 0 do
S[Pos(#10, S)]:=' '; {Nueva linea}
FillRect(Rect); {Limpia la celda}
TextOut(Rect.Left, Rect.Top, S); {Llena celda con dato memo}
end;
end;
inherited DrawColumnCell(Rect, DataCol, Column, State);
end;


end.


Gracias a mis asesores estrellas y al sitio de donde saque el código para ver el memo. Todos aportaron un poco, asi que eso se llama trabajar en en equipo,
__________________
SigmaMan
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 19:51:46.


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
Copyright 1996-2007 Club Delphi