PDA

Ver la Versión Completa : Creación de Componente basado en DBImage


Aprendiz
16-12-2004, 17:28:39
Hola a todos de nuevo,

Estoy creando un componente para solucionar un problema que ya planteé en otro hilo. Es un TDBImage al que le fuerzo a su Bitmap las propiedades TransparentMode=tmFixed, Transparent=True y TransparentColor=Color especificado por el programador.

La cosa es que no me coge el cambio de valores que le hago en el componente que he creado y no se si es que he hecho algo mal. Les dejo el código para ver si ven algo que yo no haya visto.

Saludos y Gracias.


unit DBImageSinFondo;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
DBCtrls;

type
TDBImageSinFondo = class(TDBImage)
private
FTransparent: boolean; //Bitmap Transparente
FTransparentColor: TColor; //Color del Bitmap Transparente
FTransparentMode: TTransparentMode; //Modo de captación del color transparente
procedure SetTransparent (Value: boolean);
function GetTransparent: boolean;
procedure SetTransparentColor (Value: TColor);
function GetTransparentColor: TColor;
procedure SetTransparentMode (Value: TTransparentMode);
function GetTransparentMode: TTransparentMode;
protected
{ Protected declarations }
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property TransparenteMode: TTransparentMode read GetTransparentMode write SetTransparentMode;
property Transparente: boolean read GetTransparent write SetTransparent;
property TransparenteColor: TColor read GetTransparentColor write SetTransparentColor;
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('RapidSoft', [TDBImageSinFondo]);
end;

constructor TDBImageSinFondo.Create(AOwner: TComponent);
begin
inherited Create (AOwner);
//Valores por defecto
FTransparentMode := Picture.Bitmap.TransparentMode;
FTransparent := Picture.Bitmap.Transparent;
FTransparentColor := Picture.Bitmap.TransparentColor;
end;

destructor TDBImageSinFondo.Destroy;
begin
inherited Destroy;
end;

function TDBImageSinFondo.GetTransparent: Boolean;
begin
Result := FTransparent;
end;

procedure TDBImageSinFondo.SetTransparent (Value: Boolean);
begin
FTransparent:=Value;
Picture.Bitmap.Transparent := FTransparent;
end;

function TDBImageSinFondo.GetTransparentColor: TColor;
begin
Result := FTransparentColor;
end;

procedure TDBImageSinFondo.SetTransparentColor (Value: TColor);
begin
FTransparentColor := Value;
Picture.Bitmap.TransparentColor:=FTransparentColor;
end;

function TDBImageSinFondo.GetTransparentMode: TTransparentMode;
begin
Result := FTransparentMode;
end;

procedure TDBImageSinFondo.SetTransparentMode(Value: TTransparentMode);
begin
FTransparentMode := Value;
Picture.Bitmap.TransparentMode:=FTransparentMode;
end;

end.

andres1569
16-12-2004, 17:47:18
Hola:

Mirando el código fuente del TDBImage veo que cuando se cambia de registro y por lo tanto se dispara el método DataChanged, en éste se hace Picture.Graphic := nil, lo cual seguramente anula las propiedades de transparencia que tenías.

Se me ocurre que crees un método MiPictureChanged que sustituya al que ya hay, PictureChanged (al no ser virtual no te sirve heredar de éste sino crear otro nuevo) y en el Create se lo asignas al objeto Picture:

Picture.OnChange := MiPictureChanged;

Y en dicho método es donde le asignas al Bitmap los valores de transparencia que tienes almacenados. Me queda la duda de si al asignar esos valores se volverá a lanzar el mismo método (MiPictureChanged) por lo que quizás debas usar un semáforo.

Saludos

andres1569
16-12-2004, 18:11:32
Hola:

Lo acabo de volver a mirar y la cosa no es tan fácil. Pensaba que se podría pegar alegremente todo el código de PictureChanged a MiPictureChanged pero no es así por culpa de unas variables privadas (FPictureLoaded y FDataLink) que no podemos alterar.

Bueeeno, se me ocurre algo quizás estrambótico: teniendo en cuenta que al asignar el evento MiPictureChanged al Picture (Picture.OnChange := MiPictureChanged;), dicha asignación ya está hecha en el constructor Create heredado, podríamos almacenar la referencia al método asignado en una variable del tipo TNotifyEvent:


FAnteriorNotify : TNotifyEvent;
FCambiando : Boolean;

constructor TMiDBImage.Create;
begin
inherited Create;
...
FAnteriorNotify := Picture.OnChange;
Picture.OnChange := MiPictureChanged;
...
end;

procedure TMiDBImage.MiPictureChanged;
begin
if FCambiando then EXIT;
FCambiando := TRUE;
try
Picture.Bitmap.TransparentColor:=FTransparentColor;
...
...
FAnteriorNotify(Picture);
finally
FCambiando := FALSE;
end;
end;


No sé si esto servirá ...

Saludos

Aprendiz
16-12-2004, 18:29:15
Hoa Andres, ante todo gracias por responder.

Pues funciona a medias. Te explico en un DBImage puesto sobre el formulario parece ser que lo hace bien y finalmente el color de fondo no aparece.

La verdad es que he puesto una pequeña rutina que me devuelve estos tres valores que estamos intentando cambiar del Bitmap y los cambia todos menos el TransparentColor. Con el debugger puedo ver que cuando hace la asignación del TransparentColor, no se produce ningún error pero el valor del TransparentColor no varia, se queda con el mismo valor inicial que ya tenía.

Además cuando coloco el DBImage alterado sobre un DBCtrlGrid se va todo al traste y muestra una sola imagen, la del panel que tiene el foco, transparente y el resto aparece con el desagradable fondo verde.

Sigo investigando...

Saludos.

andres1569
16-12-2004, 18:58:57
Hola Aprendiz:

Mirando la implementación de los métodos SetTransparentMode y SetTransparentColor de TBitmap, veo que ambos alteran la otra propiedad mutuamente dependiendo del valor asignado, por lo que quizás estés asignando primero el TransparentColor y si luego asignas un TransparentMode = tmAuto, el TransparentColor vuelve a clDefault.

Míralo a ver.

Saludos

andres1569
16-12-2004, 19:15:08
¡¡ Ufff !! Más cosas.

Ahora veo un fallo aquí, puesto que cada vez que el usuario altere una propiedad "Transparente" de tu componente, este cambio desencadenará inevitablemente un Picture.Changed que a su vez llamará a MiPictureChanged que reasigna todas, por lo que en los métodos SetTransparent, SetTransparentColor y SetTransparentMode tendrías que poner a TRUE el semáforo FCambiando (al terminar lo dejas en FALSE) para que no se dispare cada vez el PictureChanged, seguramente éso es lo que motiva ese comportamiento tan raro.

Saludos

Aprendiz
17-12-2004, 12:49:43
Hola,

No tranquilo, ese error no se produce, recuerda que hemos sacado las asignaciones al Bitmap de los Setters y lo pusimos directamente en MiPictureChanged con lo cual solo se ejecuta, gracias a los semáforos, una sola vez.

Saludos.

PD: De todas formas ya te digo que funciona, ahora el problema es ponerlo en un DBCtrlGrid y que también funcione para todas las fotos que carga. Esto del Replicate me está volviendo loco.