Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Alternar colores en dbgrid (https://www.clubdelphi.com/foros/showthread.php?t=71698)

Casimiro Notevi 05-01-2011 23:29:11

Cita:

Empezado por José Luis Garcí (Mensaje 386713)
Bueno siento ser pesado, pero con unos pequeños cambios os muestro lo que digo.

No, hombre, no eres pesado, al contrario, se agradece la idea, aunque no creo que me lo acepten de esa forma, pero por probar que no quede :)

José Luis Garcí 06-01-2011 17:55:02

Casimiro, puedes adaptar el mismo código, para 5 colores o para 2, cambiado solamente lo siguiente en el case

........................................C..O..L..O..R.......A......U..S..A..R
Color............terminación......Para 10.......Para 5...........Para 2
0------------------0-----------0----------0-------------0
1------------------1-----------1----------1-------------1
2------------------2-----------2----------2-------------0
3------------------3-----------3----------3-------------1
4------------------4-----------4----------4-------------0
5------------------5-----------5----------0-------------1
6------------------6-----------6----------1-------------0
7------------------7-----------7----------2-------------1
8------------------8-----------8----------3-------------0
9------------------9-----------9----------4-------------1


Ventajas de este sistema, permite un mayor control, ya que no descuadra el color, ya que el color es según el termino del Lote (asiento en tu caso y al subir o bajar no pierde el color.

Casimiro Notevi 06-01-2011 18:08:23

Cita:

Empezado por José Luis Garcí (Mensaje 386804)
Ventajas de este sistema, permite un mayor control, ya que no descuadra el color, ya que el color es según el termino del Lote (asiento en tu caso y al subir o bajar no pierde el color.

Creo que no termino de entenderlo, ¿te refieres a cambiar el color según el número de asiento?

roman 06-01-2011 18:23:38

Cita:

Empezado por Casimiro Notevi (Mensaje 386721)
Después de probar las distintas opciones aportadas por los compañeros, debo ecir que no funcionan "totalmente" bien... o yo no he sabido implementarlas, que todo puede ser.

Así que creo que la única opción es la del campo que indique el color o algo así.

No creo que funcione ninguna de las técnicas propuestas. Ja, ja, qué pesimista. Pero es que todas se basan en el "orden" en que se van pintando las celdas pero, en teoría, no es posible saber en qué orden se pintan. Dicho de otra forma, el pintado de celdas no necesariamente es secuencial sino que depende de muchos factores visuales que determinan cuáles celdas son las que requieren repintado. Por ello es que se usa el evento DrawColumnCell. Cuando la VCL detecta que una celda necesita repintarse, lanza el evento.

Por otra parte, la opción de un campo calculado que determina el coor con el que debe pintarse, pues me suena extraña. El valor de un campo calculado, normalmente, debe determinarse en términos de otros valores en el mismo registro, y si podemos usar valores en el mismo registro para saber de qué color hay que pintar, entonces no necesitamos el campo calculado sino simplemente hacer el cálculo en el evento DrawColumnCell.

// Saludos

Casimiro Notevi 06-01-2011 18:56:40

Entonces, ¿qué sugieres? :D
Que llevo tres días con esta tontería y no termina de ir bien, algo tan "simple" :S

Delphius 06-01-2011 19:41:49

No se que dirán ustedes pero creo que acabamos de encontrar el nuevo reto delphi :D

Yo digo que el gran maestros de maestros de centésimo dan Román nos ilustre ;) Yo no tener más neuronas. :o

Saludos,

roman 06-01-2011 20:00:41

Ja, ja. Yo no dije que tuviera la solución, simplemente comenté mi renuencia a creer en las ya existentes :D

Yo opino que el switch no funciona porque el pintado de celdas no necesariamente es secuencial. Sin embargo, esta técnica del switch podría usarse desde la consulta sql. Por ejemplo, en MySQL puedo hacer algo parecido a esto:

Código SQL [-]
set @asiento=0,@colorear=0;
select asiento, control, fecha, if (@asiento <> asiento, @colorear:=1-@colorear, @colorear) as colorear, @asiento:=asiento
from tabla
order by fecha, asiento, control

La columna "colorear" alterna entre 1 y 0 según cambia el valor del campo asiento, de manera que la condición en el evento DrawColumnCell se reduce a:

Código Delphi [-]
if DBGrid1.DataSource.DataSet.FieldByName('colorear').AsInteger = 1 then
  DBGrid1.Canvas.Brush.Color := clGreen;

Supongo que en Firebird también existen las variables de usuario así que podría hacerse algo similar.

// Saludos

Delphius 06-01-2011 20:13:37

¿Y que me dices de mi propuesta? Llevar una estructura que registre la distribución de pintado.

Yo para ahorrar espacio decía algo como:

HastaRegistro - Color
1 - Blanco
6 - Negro
8 - Blanco
...

Alterando esa idea se puede concebir una estructura de igual tamaño que la cantidad de registros:

RegistroNro - Color
1 - Blanco
2 - Negro
3 - Negro
...
6 - Negro
7 - Blanco
8 - Blanco

La idea es armar esta estructura analizando los registros. Cuando tenemos esta estructura ya podemos pintar el DBGrid, fila a fila en base a la evaluación del RecNo y comparandolo con RegistroNro de la estructura.

Si el evento DrawColumnCell se levanta a sus ganas, entonces forzemosle a decir, mira... tu correspondes al registro x, por tanto tu color es z.

Me dirán que es un desperdicio de memoria pero no veo otra manera.

Saludos,

roman 06-01-2011 20:21:46

Cita:

Empezado por Delphius (Mensaje 386824)
Me dirán que es un desperdicio de memoria pero no veo otra manera.

Sí, la que yo he puesto :p

Es que con tu idea hay que traerse todos los registros al cliente de una sóla vez.

// Saludos

José Luis Garcí 06-01-2011 20:36:55

Si casimiro, el color se asigna al asiento, en caso de lo que quieras es tener un Grid por colores pero por tipo de asiento (según tu post nº 1, normalmente están ordenados por fecha y no por asiento, esto funcionaría tal cual), en el otro caso, deberías usar dos variables globales, que compruebe en orden de carga si el valor del asiento cambia, asignamos primero el valor del nuevo asiento y en la segunda variable el color a o el b, lo elegimos cuando cambiamos alternando entre el a y el b, mientras tengamos el mismo número de asiento, seguimos con el mismo color al cambiar cambiamos el color.

Espero haberme explicado bien.

Delphius 06-01-2011 20:40:11

Pues, al comienzo no entendí tu idea roman. Ahora que la leo de nuevo ya le ví el truco.

¡Maestro!, me saco el sombrero. :eek: :)

Tengo la cabeza frita, no recuerdo bien si Firebird cuenta con variables de usuario y trabajar con un select. Pero la alternativa es generar un SP y allí si se puede trabajar cómodamente y aplicar lo que comentas.

Saludos,

roman 06-01-2011 20:43:20

¿Cómo sería con un procedimiento almacenado?

// Saludos

Aleca 06-01-2011 20:48:40

Cita:

Empezado por roman (Mensaje 386809)
....
Por otra parte, la opción de un campo calculado que determina el coor con el que debe pintarse, pues me suena extraña. El valor de un campo calculado, normalmente, debe determinarse en términos de otros valores en el mismo registro, y si podemos usar valores en el mismo registro para saber de qué color hay que pintar, entonces no necesitamos el campo calculado sino simplemente hacer el cálculo en el evento DrawColumnCell.

// Saludos

me parece que estos caminos no nos llevan a buen puerto, hay que replantearse la solución, a ver tenemos que encontrar la forma de que cada fila pueda tener el color para pintar y que no se cambie mientras nos movemos dentro de la grilla, el problema en la practica que veo es la posibilidad de tener muchos registros estariamos usando el tiempo en saber el color.
:confused::confused:
Casimiro, una pregunta, porque necesitas hacerlo de esta forma?

Saludos:)

roman 06-01-2011 20:53:10

Cita:

Empezado por Aleca (Mensaje 386836)
Casimiro, una pregunta, porque necesitas hacerlo de esta forma?

Quizá es muy simple mi respuesta pero yo diría que para poder distinguir fácilmente los grupos :)

// Saludos

Casimiro Notevi 06-01-2011 21:01:58

Pues sí, para separar los distintos asientos:



Dibujar es fácil, funciona perfecto con todos los ejemplos que han puesto todos los compañeros, el problema viene cuando te mueves por el grid arriba y abajo, llegas al final y al principio, etc.

El ejemplo de Román no he podido probarlo porque desconozco el tema de las variables de usuario en firebird, estoy buscando información al respecto.

Aleca 06-01-2011 21:05:37

Cita:

Empezado por roman (Mensaje 386839)
Quizá es muy simple mi respuesta pero yo diría que para poder distinguir fácilmente los grupos :)

// Saludos

lo preguntaba por que a lo mejor puede haber otra solución de acuerdo al objetivo que tenga.
Por las dudas...:confused::confused:
Saludos :)

Aleca 06-01-2011 21:09:33

a ver, otra pregunta tonta, puede haber muchos registros?
lo pregunto porque creo que hay que anclar el color de la fila con el registro.:confused:

Delphius 06-01-2011 21:14:26

El procedimiento almacenado para Firebird sería algo como este (probado en una tabla de prueba que tengo):

Código SQL [-]
SET TERM ^ ;

CREATE PROCEDURE PINTAR_TABLA 
RETURNS (
    NEW_COLOREAR INTEGER,
    NEW_FECHA DATE,
    NEW_NOMBRE VARCHAR(30),
    NEW_ID INTEGER)
AS
DECLARE VARIABLE VAR_COLOREAR INTEGER;
DECLARE VARIABLE VAR_ID INTEGER;
begin
  /* Procedure Text */
  var_colorear = 0;
  var_id = 0; /* sería el campo asiento */
  for select ID, NOMBRE, FECHA from tabla1 order by ID, FECHA, NOMBRE
  into :new_id, :new_nombre, :new_fecha
  do
    /* calculamos */
    begin
      if (var_id <> :new_id) then var_colorear = 1 - var_colorear;
      new_colorear = var_colorear;
      var_id = :new_id;
      suspend;
    end
end
^

SET TERM ; ^

GRANT SELECT ON TABLA1 TO PROCEDURE PINTAR_TABLA;

GRANT EXECUTE ON PROCEDURE PINTAR_TABLA TO SYSDBA;

Saludos,

Delphius 06-01-2011 21:22:33

Basicamente la idea es que el campo "Colorear" alterne entre 1 y 0. Se va recorriendo la consulta ordenada por fecha y asiento almacenando los valores en una variable. Si resulta ser que el valor del asiento del actual registro es distinto al de la variable se altera el valor del campo colorear por su "negado". En otro caso queda el valor anterior.

Luego, cuando se va pintando el DBGrid, se evalúa el valor del campo Colorear y si 1 o 0 se establece un color o otro y se pinta.

Saludos,

Delphius 06-01-2011 21:50:54

Ha... y como PLUS :) , la técnica que me inspiró roman da incluso para trabajar con más de dos colores.

Siendo N la cantidad de colores, podemos alternar cíclicamente los colores haciendo algo como:

Código Delphi [-]
ColorElegido = Color mod N;

Siendo Color una variable que se incrementa cuando se cumple la condición:
Código Delphi [-]
(Asiento <> var_Asiento)

Espero que se entienda la idea ;)

De ese modo tendremos que el valor del hipotético campo "Colorear" irá alternando desde 0 a N-1 cada vez que detecte un nuevo asiento.

EDITO:
Esto se ha convertido en un monólogo :D

Saludos,

Casimiro Notevi 06-01-2011 22:51:55

Buenísima la idea, lo he probado y funciona perfectamente :) .... ... ... peeerooooo... ... ... no me sirve :(
No puedo usar un procedimiento almacenado porque en pantalla el usuario selecciona una serie de opciones de filtro y el select sql se crea dinámicamente :(
No se me ocurre cómo pasar ese select a un procedimiento, salvo crear el procedure dinámicamente, lanzarlo y borrarlo después. Hacer un "create or alter procedure"... ... ... puede ser

Código Delphi [-]
procedure TFapuntes.CargarDiario(iParametro: integer);
var
  cSql : string;
begin
{ TODO 3 -oampc -cControlar : Hace falta controlar los tipos de usuarios, por si tiene permisos para verlos o no. }
  DMapuntes.QRdiario.Close;
  cSql := 'select * from tbapuntes where codigoempresa= :codigoempresa and ejercicio= :ejercicio ';
  case iParametro of
    0,1,2,3,4: cSql := cSql + ' and codigoestadoapunte=2 ';  // 1.definitivo  2.borrador
    5: cSql := cSql + ' and codigoestadoapunte=1 ';  // 1.definitivo  2.borrador
  end;
  case iParametro of
    0,2,3: cSql := cSql+' and fechaasiento  between :fechadesde and :fechahasta ';
    1: cSql := cSql+' and fechacreacion= :fechacreacion and horacreacion>= :horacreacion ';
  end;
  case iParametro of
    4: cSql := cSql + ' and (codigousuariocreacion='+IntToStr(fmain._iCodigoUsuario_)+
                       ' or codigousuariomodificacion='+IntToStr(fmain._iCodigoUsuario_)+')';
  end;
  cSql := cSql + ' order by codigoempresa, ejercicio, numeroasiento, lineaasiento';
  //
  DMapuntes.QRdiario.SelectSQL.Text := cSql;
  //
  DMapuntes.QRdiario.Params[0].AsInteger := Fmain._iCodigoEmpresa_;
  DMapuntes.QRdiario.Params[1].AsInteger := Fmain._iCodigoEjercicio_;
  //
  case iParametro of
    0:begin  // cd_config
        DMapuntes.QRdiario.Params[2].AsDate := edDfecD.Date;
        DMapuntes.QRdiario.Params[3].AsDate := edDfecH.Date;
      end;
    1:begin  // cd_sesion
        DMapuntes.QRdiario.Params[2].AsDate := Trunc(fmain._dFechaInicioSesion_);
        DMapuntes.QRdiario.Params[3].AsTime := Frac (fmain._dFechaInicioSesion_);
      end;
    2:begin  // cd_hoy
        DMapuntes.QRdiario.Params[2].AsDate := getFechaServidor;
        DMapuntes.QRdiario.Params[3].AsDate := getFechaServidor;
      end;
    3:begin  // cd_ftrabajo
        DMapuntes.QRdiario.Params[2].AsDate := fmain._dFechaTrabajo_;
        DMapuntes.QRdiario.Params[3].AsDate := fmain._dFechaTrabajo_;
      end;
  end;
  //
  DMapuntes.QRdiario.Open;
  //
  grDiario.SetFocus;
end;

roman 06-01-2011 22:55:20

Dicho a bote pronto, ¿no puedes hacer un procedimiento almacenado al que le pases como parámetros los filtros que escoge el usuario?

// Saludos

Delphius 06-01-2011 22:59:44

Cita:

Empezado por roman (Mensaje 386857)
Dicho a bote pronto, ¿no puedes hacer un procedimiento almacenado al que le pases como parámetros los filtros que escoge el usuario?

// Saludos

Pues yo creería que si. No veo porqué no trasladar los parámetros y filtros de entrada al SP y después hacer simplemente algo como

Código SQL [-]
select * from MiProcedimientoAlmacenado(Param1, Param2 ....)

Para tener el conjunto de datos.

Saludos,

Casimiro Notevi 06-01-2011 23:13:32

Sí, en teoría, sí. El caso es que tengo ya la cabeza como un bombo dándole vueltas a esto desde hace varios días, voy a comer algo y desenchufo un rato, a ver si después lo veo más claro.
Gracias!!!!!!

Chris 06-01-2011 23:30:45

Mejorando código....

Código Delphi [-]
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
    background_colors: array[0..1] of TColor = (clBtnFace, clWhite);
begin
if Dataset.FieldByName('asiento').Value <> UltimoValor then
    BoolSwitch := (not BoolSwitch);

TDBGrid(Sender).Canvas.Brush.Color := background_colors[BoolSwitch];

// el grupo ya fue pintado?
if Pos(Format('-%s-', [Dataset.FieldByName('asiento').Value]), GrupoImpar) > 0 then
    TDBGrid(Sender).Canvas.Brush.Color := background_colors[0];
   
TDBGrid(Sender).DefaultDrawColumnCell( ... );
UltimoValor := Dataset.FieldByName('asiento').Value;

// guarlar una lista de los grupos impares
if (not BoolSwitch) and (Pos(Format('-%s-', [Dataset.FieldByName('asiento').Value]), GrupoImpar) = 0) then
    GrupoImpar := (GrupoImpar + Format('-%s-', [Dataset.FieldByName('asiento').Value]);
...
end;

Es un gasto de memoria, es cierto. Pero la solución en el código es una simplificación de la solución primera propuesta por delphius.

Aún no funciona? Dinos que esto ya lo tomamos como reto

EDITO: Aclaro que GrupoImpar es una variable global privada

fjcg02 06-01-2011 23:42:43

Hola de nuevo.

No quiero ser pesado, pero ya lo comenté en un post anterior. Se hace un procedimiento almacenado y se llama al mismo poniendo la where que se quiera, ya que puede ser invocado como una tabla o query. esta where puede ser montada 'al vuelo'.

Código SQL [-]
SET TERM ^ ;

CREATE OR ALTER PROCEDURE PRUEBA 
returns (
    idpresupuesto integer,
    color integer)
as
declare variable widpresupuesto integer;
begin
  /* Procedure Text */
  widpresupuesto = -1000;
  for
  SELECT IDPRESUPUESTO FROM b_lineapresupuesto order by idpresupuesto
  into :idpresupuesto
  do
  begin
    if (widpresupuesto = idpresupuesto) then
    begin
      if (color = 1) then COLOR = 1;
      else color = 0;
    end
    else
    begin
      if (color = 1) then COLOR = 0;
      else color = 1;
    end
    widpresupuesto=idpresupuesto;
    suspend;
  end
end^

SET TERM ; ^
Llamadas
Código SQL [-]
SELECT * from prueba WHERE IDPRESUPUESTO > 40

ó 

SELECT * from prueba WHERE IDPRESUPUESTO >= 40 AND IDPRESUPUESTO <= 200

Espero que sea de utilidad.

Saludos
Aupa Casi, no desfallezcas ahora !!

Chris 06-01-2011 23:48:39

Cita:

Empezado por Delphius (Mensaje 386859)
Pues yo creería que si. No veo porqué no trasladar los parámetros y filtros de entrada al SP y después hacer simplemente algo como

Código SQL [-]
select * from MiProcedimientoAlmacenado(Param1, Param2 ....)

Para tener el conjunto de datos.

Saludos,

De hecho en Firebird un procedimiento almacenado puede ser usado como un select cualquiera, eligiendo los campos y las condiciones que deben complirse para devolver cierto grupo de registros. Incluso se le puede establecer un orden. El único inconveniente es que es un poco más lento que cualquier otro select hecho directamente sobre una tabla.

Código SQL [-]
select from campo1, campo2, campo3 from procedimiento_almacenado where campo1=condificion_usuario order by campo_n

Saludos,
Chris

fjcg02 06-01-2011 23:50:21

Huelo que estamos llegando a tocarlo con la punta de los dedos...

Casi lo tenemos ...

Delphius 06-01-2011 23:53:06

Cita:

Empezado por Casimiro Notevi (Mensaje 386862)
Sí, en teoría, sí. El caso es que tengo ya la cabeza como un bombo dándole vueltas a esto desde hace varios días, voy a comer algo y desenchufo un rato, a ver si después lo veo más claro.
Gracias!!!!!!

Tu tranqui.

Prueba y evalúa las opciones. Si tienes problemas nos avisas y le caemos a madrazos a tu jefe y/o cliente por ese requerimiento :D

Si te funciona, ya sabes... me envías un jamón (la pata entera, por supuesto) por correo ;) :D :p

Saludos,

Aleca 06-01-2011 23:58:34

Cita:

Empezado por fjcg02 (Mensaje 386869)
Huelo que estamos llegando a tocarlo con la punta de los dedos...

Casi lo tenemos ...

si es así en horabuena, se esta siendo rogar...:D

fjcg02 07-01-2011 00:20:14

Repasando el hilo completo, Delphius ya daba el 80 % de la solución cuando en su post adjuntaba el código del procedimiento almacenado.

Sólo faltaba tal y como apuntaba Chris, saber que un procedimiento almacenado se puede llamar igual que cualquier tabla o vista, añadiéndole las condiciones que se necesiten al WHERE.

Un saludo

Delphius 07-01-2011 00:34:05

Debo decir que no hubiera sido posible la escritura del SP sin la ayuda de román cuando presentó esa consulta.

Por ello estoy dispuesto a compartir la mitad del jamón con el maestro román. :) :D ;)

Saludos,

Chris 07-01-2011 00:43:13

Cita:

Empezado por fjcg02 (Mensaje 386872)
Repasando el hilo completo, Delphius ya daba el 80 % de la solución cuando en su post adjuntaba el código del procedimiento almacenado.

Sólo faltaba tal y como apuntaba Chris, saber que un procedimiento almacenado se puede llamar igual que cualquier tabla o vista, añadiéndole las condiciones que se necesiten al WHERE.

Un saludo

Puede ser que ya se haya encontrado una solución, pero no es la optima realmente. No es muy buena idea que la base de datos funcione de muleta de un programador que no pudo solucionar un problema de la GUI. Agregar un campo más lo único que hará es aumentar la cantidad de datos que deben intercambiarce y para rematar, usando un procedimiento almacendado, la consulta se vuelve más lenta. Con estos dos problemas, todos tus usuarios juntos podrían perder mucho más tiempo del que no quisiste tomarte en moldear una mejor idea.

Obviamente, es decisión de Casimiro en este caso tomar un camino para su solución, pero yo sigo pensando en que es mucho mejor seguir trabajando del lado del código de la GUI en luegar de utilizar la base de datos como solución.

Delphius 07-01-2011 01:03:37

Cita:

Empezado por Chris (Mensaje 386875)
Puede ser que ya se haya encontrado una solución, pero no es la optima realmente. No es muy buena idea que la base de datos funcione de muleta de un programador que no pudo solucionar un problema de la GUI. Agregar un campo más lo único que hará es aumentar la cantidad de datos que deben intercambiarce y para rematar, usando un procedimiento almacendado, la consulta se vuelve más lenta. Con estos dos problemas, todos tus usuarios juntos podrían perder mucho más tiempo del que no quisiste tomarte en moldear una mejor idea.

Obviamente, es decisión de Casimiro en este caso tomar un camino para su solución, pero yo sigo pensando en que es mucho mejor seguir trabajando del lado del código de la GUI en luegar de utilizar la base de datos como solución.

Nunca se ha dicho que sea la más óptima, que sea la mejor, o que fuese la única alternativa.
Es sólo una posibilidad más que se baraja y debo decir que en buena parte tiene su simpleza.

Quizá un SP no se tan rápido que una consulta. Quizá se pierda un poco de velocidad y perfomance cuando se tengan varios registros y sean muchos clientes quienes estén atacando el servidor pero la posibilidad de que esté el SP ayuda a que buena parte del código sea más simple.

Si el motor tiene la capacidad y los datos necesarios para ayudar a facilitar algunas operaciones del lado del cliente es más que una buena posibilidad de evaluarlo. ¿No es acaso una de las reglas que un desarrollador debe siempre considerar?

Si el servidor puede asumir esa tarea y puede darnos los datos pre-masticados que la haga.... para todo lo demás existe mastercard... este... digo el sistema cliente. :D

No se trata de una chapuza como lo quieres vender, ni que el programador es ineficiente o incompetente por no haber logrado algo por otra vía. Si tanto te preocupa encontrar una solución que no esté vinculada con la base de datos y sea por código yo ya había indicado una vía, que me tomo la molestia de corregir:

Disponer de una estructura, una lista, a modo del campo ficticio "Colorear" y llenar esta lista con los 1 o 0 (o el color, o lo que quieran) para que luego al momento de pintar el DBGrid pueda recuperarse este dato y saber de que color pintarlo.
El punto es que NECESARIAMENTE se debe contar con toda la información de todos los registros para saber de que color pintar. No puede verse y atacar el problema considerando el registro de forma individual, ya que su color está relacionado con su predecesor y es necesario mantener en memoria, de alguna forma, el color asignado para que a efectos de un desplazamiento podamos volver al estado original.

Saludos,

Casimiro Notevi 07-01-2011 01:13:33

Cita:

Empezado por Chris (Mensaje 386864)
[..]
if Dataset.FieldByName('asiento').Value <> UltimoValor then
BoolSwitch := (not BoolSwitch);



C
reo que se está llegando a la conclusión de que esa parte es la que no funciona en este sistema, no se puede comparar con el valor del "último valor" porque puede ser cualquier registro, por ejemplo cuando ha llegado al último registro y ahora se posiciona en el primero, los colores pueden ser iguales, o no, depende de si el número de "asientos" es par o impar.
O sea, pintarlo, lo pinta perfecto, tanto ese método como todos los demás que se han sugerido, pero en cuanto empiezas a moverte por el grid arriba y abajo, con teclas o con el ratón, yendo al primero o al último con ctrl-inicio y ctrl-fin, página arriba y abajo, etc. siempre acaba descontrolando los colores por lo dicho anteriormente, el "anterior" no tiene por qué ser el que está "antes" en el dbgrid.

Entonces las únicas soluciones posibles son las que sacan el color del propio registro, independientemente de lo que tengan los otros registros anteriores o posteriores.
Ya sea mediante procedimiento almacenado, tabla en memoria, etc.

Bueno, esto que comento es lo que me parece según lo visto, puedo estar totalmente equivocado y ahora alguno expone un código que consigue el resultado esperado.

Chris 07-01-2011 05:07:05

[quote=Delphius;386876] ... ... ... [/]
Es obvio que te molestó mi comentario. Sorry, pero es mi opinión y mi filosofía de desarrollo. Por lo que tú digas, no la cambiaré porque no creo estar equivocado.

Tú bien sabes -lo has dicho- que existe una solución sin recurrir a la base de datos, y si esa fuera matar moscas con cañonazos, pues que así sea. Aveces, algunas "tonterías" -desde el punto de vista de la GUI- necesitan cientos de línea y docenas de horas en moldearse."

Cita:

Empezado por Delphius (Mensaje 386876)
Si el motor tiene la capacidad y los datos necesarios para ayudar a facilitar algunas operaciones del lado del cliente es más que una buena posibilidad de evaluarlo. ¿No es acaso una de las reglas que un desarrollador debe siempre considerar?

Si el servidor puede asumir esa tarea y puede darnos los datos pre-masticados que la haga.... para todo lo demás existe mastercard... este... digo el sistema cliente. :D

Aquí estamos totalmente deacuerdo. Pero esa ley no la debes tomar universalmente. Desde mi filosofía, es adecuado implementar esta regla para la lógica de negocios de la aplicación, no para ayudarte a pintar la GUI. Si tienes problemas para pintar la GUI, pídele ayuda a otro programador, no a la base de datos.

Cita:

Empezado por Delphius (Mensaje 386876)
Quizá un SP no se tan rápido que una consulta. Quizá se pierda un poco de velocidad y perfomance cuando se tengan varios registros y sean muchos clientes quienes estén atacando el servidor pero la posibilidad de que esté el SP ayuda a que buena parte del código sea más simple.

Acaso valdrá la pena que tus usuarios queden colgados por N segundos solo porque un programador prefirió que su código fuera más simple?

Cita:

Empezado por Delphius (Mensaje 386876)
No se trata de una chapuza como lo quieres vender, ni que el programador es ineficiente o incompetente por no haber logrado algo por otra vía. Si tanto te preocupa encontrar una solución que no esté vinculada con la base de datos y sea por código yo ya había indicado una vía...

Cómo tarea es una solución ingeniosa, eso sin duda. Para un sistema en producción, es deficiente. Punto! Mejor sigamos por tu vía, es mucho mejor.

Cita:

Empezado por Delphius (Mensaje 386876)
El punto es que NECESARIAMENTE se debe contar con toda la información de todos los registros para saber de que color pintar. No puede verse y atacar el problema considerando el registro de forma individual, ya que su color está relacionado con su predecesor y es necesario mantener en memoria, de alguna forma, el color asignado para que a efectos de un desplazamiento podamos volver al estado original.

Saludos,

Has terminado muy bien. Sigamos con el hilo, está cada vez más interesante. No lo desvirtuemos.

Chris 07-01-2011 05:10:29

Cita:

Empezado por Casimiro Notevi (Mensaje 386878)
[font=monospace]
Creo que se está llegando a la conclusión de que esa parte es la que no funciona en este sistema, no se puede comparar con el valor del "último valor" porque puede ser cualquier registro, por ejemplo cuando ha llegado al último registro y ahora se posiciona en el primero, los colores pueden ser iguales, o no, depende de si el número de "asientos" es par o impar.
O sea, pintarlo, lo pinta perfecto, tanto ese método como todos los demás que se han sugerido, pero en cuanto empiezas a moverte por el grid arriba y abajo, con teclas o con el ratón, yendo al primero o al último con ctrl-inicio y ctrl-fin, página arriba y abajo, etc. siempre acaba descontrolando los colores por lo dicho anteriormente, el "anterior" no tiene por qué ser el que está "antes" en el dbgrid.

Entonces las únicas soluciones posibles son las que sacan el color del propio registro, independientemente de lo que tengan los otros registros anteriores o posteriores.
Ya sea mediante procedimiento almacenado, tabla en memoria, etc.

Bueno, esto que comento es lo que me parece según lo visto, puedo estar totalmente equivocado y ahora alguno expone un código que consigue el resultado esperado.

Solo una pregunta. Independientemente del número en que se inicie el valor del campo ASIENTO, ya sea 5,6,7, etc. los números siempre serán consecutivos? Si fuese así, puedes utilizar el valor del número más bajo. Hacer una resta y del residuo calcular si es par o impar. Par un color, impar otro color.

Delphius 07-01-2011 06:24:33

Cita:

Empezado por Chris (Mensaje 386883)
Es obvio que te molestó mi comentario. Sorry, pero es mi opinión y mi filosofía de desarrollo. Por lo que tú digas, no la cambiaré porque no creo estar equivocado.

Y si me molestó, porque lanzaste un comentario a modo de indirecta a todo aquella persona que ha propuesto una ALTERNATIVA. Repito: ALTERNATIVA, no una solución que sea perfecta, bonita y que te caiga bien a tus propios gustos.

Estamos presentando alternativas, no sabíamos que te tenía que caer bien a vos.

Luego venía el debate de sus pros y contras.

Cita:

Empezado por Chris (Mensaje 386883)
Tú bien sabes -lo has dicho- que existe una solución sin recurrir a la base de datos, y si esa fuera matar moscas con cañonazos, pues que así sea. Aveces, algunas "tonterías" -desde el punto de vista de la GUI- necesitan cientos de línea y docenas de horas en moldearse."

Hay veces que debemos matar moscas a cañones, y otras veces se puede llegar a un término medio no con un cañón pero si con un mosquete y para otras será válida un simple revólver .22.

Tu que eres el mega chingón desarrollador, y tanto se ve que sabes deberías estar bien al tanto que en ocasiones no existe el blanco o el negro y debe encontrarse una solución en términos grises.

Cita:

Empezado por Chris (Mensaje 386883)
Aquí estamos totalmente deacuerdo. Pero esa ley no la debes tomar universalmente.

En ningún momento dije que haya que tomarla univesalmente. Más bien dije que mientras que nos permita aplicarla deberías considerarla.
Algunas reglas están para romperse, otras no.. y otras tantas a medias.

Para alguien que pretende decir que no debería tomarse universalmente me sorprende que intentes convencer que la solución pase únicamente por el lado del cliente.
A ver chiquito... estamos debatiendo pero parece que a vos no te agrada que otros presentemos otras vías posibles de encararlo.

Allí si tu tienes tu estilo, al menos otros estamos buscando darles giros al asunto y no quedarnos monotemáticos.

Cita:

Empezado por Chris (Mensaje 386883)
Desde mi filosofía, es adecuado implementar esta regla para la lógica de negocios de la aplicación, no para ayudarte a pintar la GUI. Si tienes problemas para pintar la GUI, pídele ayuda a otro programador, no a la base de datos.

¿Y no crees que Casi ha pedido ayuda y aquí entre todos, cada uno desde su lugar hizo o está haciendo un esfuerzo?
Tu pretendes tildar a Casi y a los demás como incompetente. Evita esas indirectas molestas... aqui ninguno viene con aires de traer la superioridad...

Y si no has sabido interpretar algunas cosas que se han dicho con humor... bueno, eso ya es otra cosa.

Cita:

Empezado por Chris (Mensaje 386883)
Acaso valdrá la pena que tus usuarios queden colgados por N segundos solo porque un programador prefirió que su código fuera más simple?

No podemos asegurar que sea N segundos, quizá sea N/2 lo cual sería un factor considerable. Y te digo que en ocasiones es preferible que se la aguanten un poquito antes que tener un código que podría tener la posibilidad de estallar en un futuro y ser inestable en cuanto se añadan nuevas mejoras o adiciones.

Sabes que existe algo llamado KISS... a lo siento... tu prefieres seguir rompiéndote la cabeza y no intentar darle un giro a tus ideas. Bien por ti, si quieres seguir complicándote.

Cita:

Empezado por Chris (Mensaje 386883)
Cómo tarea es una solución ingeniosa, eso sin duda. Para un sistema en producción, es deficiente. Punto! Mejor sigamos por tu vía, es mucho mejor.

¿Y como sabes y estás tan seguro que tan deficiente eres? ¿Que carajos sabes de los factores que inducen a la perfomance a la que verá sometido el sistema de Casimiro? Quizá esta consulta la use unas pocas personas, muy pocas veces al día, quizá tenga un buen servidor...
Hay más que mirar, y no necesariamente habrá una perdida considerable de perfomance.

Y allí si digo... punto final.

Cita:

Empezado por Chris (Mensaje 386883)
Sigamos con el hilo, está cada vez más interesante. No lo desvirtuemos.

Si, sigamos con el hilo... que no tiene sentido discutir, menos con alguien que pretende ponerle punto final a un debate de ideas.

Te aviso además, que no fui el iniciador y motivador principal de la solución por el lado de la base de datos... fue román, si tienes algo que decir y objetar crítica a él. Yo solamente seguí su planteo y propuse una ALTERNATIVA.

REPITO Y SOSTENGO HASTA EL CANSANCIO... HABLAMOS DE ALTERNATIVAS.. NO DE QUIEN SE LLEVA EL PREMIO A LA RAZÓN. La verdadera razón se la doy a Dios.

Saludos Cris....

Saludos a los demás.

fjcg02 07-01-2011 09:09:38

Demonios, qué caro se está poniendo el jamón :eek:

Que no cunda el pánico. Independientemente de la solución que se adopte, hay que tener en cuenta que los partícipes en este hilo no somos aprendices, y la verdad, hemos tardado en encontrar la solución; desde Casimiro que lo abrió al último participante. Y sí, parecía cosa de niños, pero realmente no era así.

Una vez tengamos una sóla o infinidad de soluciones, dejémosle a quien tiene que resolver el problema que lo resuelva como mejor crea conveniente, ya que de sus sistema, de sus usuarios y de sus problemáticas es él quien tiene el máximo de información.

La solución planteada desde la parte del servidor, puede ser tan buena como otra cualquiera, dependerá de la cantidad de veces que ese proceso se lanza, del equilibrio entre coste-beneficio, de lo pijo que sea el usuario, ... como bien comentabais antes.


Saludos

duilioisola 07-01-2011 10:57:55

Yo lo he logrado con el código que puse anteriormente. (Modificado un poco)




Resumiendo:
Poner AutoCalcFields = False;
Creando un campo calculado
Creando el evento OnCalcFields

Código Delphi [-]
{En el DataModule}
{Campo calculado SOMBRA integer}
{Propiedad AutoCalcFields=False}
{Variable global al DataModule (private de DMMayor) Sobra boolean}
{Variable global al DataModule (private de DMMayor) ValorAnterior string}

procedure TDMMayor.xMayorBeforeOpen(DataSet: TDataSet);
begin
   Sombra := False;
   ValorAnterior := '';
end;

procedure TDMMayor.xMayorCalcFields(DataSet: TDataSet);
begin
   {El campo calculado se inicializa a 0. Solo recalculo si es este valor}
   {ValorAnterior siempre guarda el valor del ultimo registro}

   {Si todavía no he establecido el valor del campo calculado}
   if (DataSet.FieldByName('SOMBRA').AsInteger = 0) then
   begin
      {Si el valor cambia, alterno el valor de Sombra}
      if (ValorAnterior <> DataSet.FieldByName('ASIENTO').AsString) then
      begin
         Sombra := not Sombra;
         ValorAnterior := DataSet.FieldByName('ASIENTO').AsString;
      end;
      
      if (Sombra) then
         DataSet.FieldByName('SOMBRA').AsInteger := 1
      else
         DataSet.FieldByName('SOMBRA').AsInteger := 2;
   end;
end;

{En el Formulario}

procedure TFCMayor.DBGConsultaDrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: integer; Column: TColumn; State: TGridDrawState);
begin
  with TDBGrid(Sender) do
  begin
     if (gdFocused in State) then //Si tiene el foco
     begin
        Canvas.Font.Color := clWhite;
        Canvas.Brush.Color := clHighlight;
     end
     else
     begin
        {Sombra puede ser 1 o 2. Si está a 0 no esta establecido}
        if (DataSource.DataSet.FieldByName('SOMBRA').AsInteger = 2) then
        begin
           Canvas.Font.Color := clBlack;
           Canvas.Brush.Color := clYellow;
        end
        else
        begin
           Canvas.Font.Color := clBlack;
           Canvas.Brush.Color := clInfoBk;
        end;
     end;
     DefaultDrawColumnCell(Rect, DataCol, Column, State);
  end;
end;


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

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