Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Comportamiento extraño al colorear un ListView (https://www.clubdelphi.com/foros/showthread.php?t=57766)

Ziara 26-06-2008 18:34:46

Comportamiento extraño al colorear un ListView
 
Hola a todos!

Tengo un ListView en el cual, dependiendo de una condición, las filas se pinta de un color u otro, y todo OK en tiempo de ejecución.

Pero cuando termina de sacarme las filas y desplazo el scroll vertical para mirar las filas que quedan arriba o abajo de la pantalla de visualización del ListView, el color pintado se me desaparece, es decir, se me queda el color por defecto designado, que es el color de las letras en negro y el fondo en blanco.

Me ocurre lo mismo cuando pincho sobre una de las lineas o cuando minimizo la aplicación y la vuelvo a restaurar (me desaparece los colores de las filas, y me dejan las por defecto).

No sé que puede ser...?

Gracias de antemano.

maeyanes 26-06-2008 19:04:35

Hola...

Puedes explicar exactamente como haces ese coloreado de las filas?

Que código usas y desde donde usas ese código (evento, método redefinido, etc...)



Saludos...

Ziara 26-06-2008 19:35:51

>Puedes explicar exactamente como haces ese coloreado de las filas?

>Que código usas y desde donde usas ese código (evento, método redefinido, etc...)

Hola,

estoy programando en builder6, tengo un ListView en un Form1 y en el Unit.h asociado llamo al evento ListViewCustomDrawItem del siguiente modo:

Código:

void __fastcall TForm1::ListViewCustomDrawItem(TCustomListView *Sender,
      TListItem *Item, TCustomDrawState State, bool &DefaultDraw)
{
 Sender->Canvas->Font->Color = clRed;

 if (snf2->Proto() == "TCP")
 {
  Sender->Canvas->Font->Color = clGreen;
 }
  if (snf2->Proto() == "UDP")
 {
  Sender->Canvas->Font->Color = clBlue;
 }
 if (snf2->Proto() == "ARP")
 {
  Sender->Canvas->Font->Color = clPurple;
 }
}

donde snf2 es un objeto de una clase y Proto() es un método de dicho clase, y snf2->Proto() me devuelve el tipo de protocolo que dependiendo del que sea se pinta las letras de un color u otro.

Lo que sucede lo he mencionado antes, que en tiempo de ejecución funciona bien, pero al terminar de sacarme las filas y muevo el scroll vertical o pincho sobre alguna fina o minimizo la aplicaciones todas las filas me aparece el color por defecto, que en este caso es rojo.

Alguien sabe por qué? :(

maeyanes 26-06-2008 19:55:11

Hola...

Vaya, no había leido bien el mensaje xDDDD

snf2 es un objeto único? O existe uno por cada Item en el ListView?


Saludos...

escafandra 26-06-2008 23:52:25

Cita:

Empezado por Ziara (Mensaje 296496)
Código:

void __fastcall TForm1::ListViewCustomDrawItem(TCustomListView *Sender,
      TListItem *Item, TCustomDrawState State, bool &DefaultDraw)
{
 Sender->Canvas->Font->Color = clRed;

 if (snf2->Proto() == "TCP")
 {
  Sender->Canvas->Font->Color = clGreen;
 }
  if (snf2->Proto() == "UDP")
 {
  Sender->Canvas->Font->Color = clBlue;
 }
 if (snf2->Proto() == "ARP")
 {
  Sender->Canvas->Font->Color = clPurple;
 }
}


Prueba a añadir en tu código DefaultDraw = false;
Código:

void __fastcall TForm1::ListViewCustomDrawItem(TCustomListView *Sender,
      TListItem *Item, TCustomDrawState State, bool &DefaultDraw)
{
 Sender->Canvas->Font->Color = clRed;

 if (snf2->Proto() == "TCP")
 {
  Sender->Canvas->Font->Color = clGreen;
 }
  if (snf2->Proto() == "UDP")
 {
  Sender->Canvas->Font->Color = clBlue;
 }
 if (snf2->Proto() == "ARP")
 {
  Sender->Canvas->Font->Color = clPurple;
 }
 DefaultDraw = false;
}

Saludos.

Ziara 01-07-2008 17:22:13

Buenas tardes!

Cita:

Snf2 es un objeto único? O existe uno por cada Item en el ListView?
Es un objeto único.
Cita:

Prueba a añadir en tu código DefaultDraw = false;
He probado a añadir esto en el código, y cuando ejecuto la aplicación, los paquetes que se van capturando no aparecen visibles, es decir, sé que captura paquetes ya que el scroll vertical va bajando, pero no los visualizo en la pantalla, parecen invisibles, que podría ser?

Gracias.

maeyanes 01-07-2008 17:52:43

Hola...

Me imagino que lo que estás haciendo es como un registro de actividad de lo que recibe el objeto, no es así?

Entonces, lo que sucede es que el componente al redibujar siempre va a leer el último valor que tiene el objeto, es por eso que cuando haces un scroll ya no se ven como cuando se insertaron la primera vez...

Para esto podrías usar la propiedad Data del TListItem (el ejemplo te lo pongo en Delphi, pero deberías poder traducirlo a C sin problemas):

Código Delphi [-]
// Agregas un TListItem nuevo:
with ListView1.Items.Add do
  if snf2.Proto = 'TCP' then
    Data := Pointer(0)
  else
    if snf.Proto = 'UDP'
      Data := Pointer(1)
    else
      Data := Pointer(2);

// Ahora en el evento OnCustomDrawItem:
procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView; Item: TListItem;
  State: TCustomDrawState; DefaultDraw: Boolean);
begin
  case Integer(Item.Data) of
    0:
      Sender.Canvas.Font.Color := clGreen;
    1:
      Sender.Canvas.Font.Color := clBlue;
    2:
      Sender.Canvas.Font.Color := clPurple
  else
    Sender.Canvas.Font.Color := clRed
  end
end;

Ya con esto cada que hagas un scroll se deben dibujar bien los items en la lista...


Saludos...

Ziara 02-07-2008 16:44:17

Buenas,

Cita:

Me imagino que lo que estás haciendo es como un registro de actividad de lo que recibe el objeto, no es así?
mmm, creo que te entiendo y creo que si, en una clase llamada Sniffer hay una serie de métodos que hace la función de capturar paquetes, esto lo tengo en un Unit3 (por ejemplo) y es donde voy incluyendo los paquetes en el ListView.

Como el ListView lo tengo en Form1 en Unit1 pues traslado el valor que me interesa con snf->Proto() donde snf es un objeto de la clase Snifer, así paso el valor que me interesa (en este caso el protocolo) del Unit3 al Unit1 para usarlo dentro del método de ListViewCustomDrawItem como lo he indicado anteriormente.

Según el código:

Código:

// Agregas un TListItem nuevo:
with ListView1.Items.Add do
 if snf2.Proto = 'TCP' then
    Data := Pointer(0)
else
    if snf.Proto = 'UDP'
      Data := Pointer(1)
    else
      Data := Pointer(2);

donde lo agrego? en Unit1 únicamente tengo el metodo
ListViewCustomDrawItem.

No lo tengo muy claro. Gracias

maeyanes 02-07-2008 17:45:05

Hola...

Ese código lo vas a poner en donde agregas los items en el ListView... Busca en tu código donde haces ListView.Items.Add y ahí lo puedes adaptar o agregar...

Por ejemplo si tienes en tu código algo como:

Código:

TListItem AItem = ListView->Items->Add;
AItem->Caption = snf2->Proto();
/* Aquí agregas el código */
if (AItem->Caption = '"TCP")
{
  AItem->Data = Pointer(0);
}
else
  if (AItem->Caption = "UDP")
  {
    AItem->Data = Pointer(1);
  }
  else
  {
    AItem->Data = Pointer(2);
  }

Ahora, tiene años que no programo nada en C++, así que el casting de entero a puntero me imagino que no se hace de la forma en que lo puse...


Saludos...

Ziara 09-07-2008 21:25:14

Buenas tardes!

Todavía no lo tengo muy claro, te voy a plantear mis dudas.

Cita:

Ese código lo vas a poner en donde agregas los items en el ListView... Busca en tu código donde haces ListView.Items.Add y ahí lo puedes adaptar o agregar...
Bien, el ListView lo tengo en un Unit4, por ejemplo, que se ejecuta como un hilo donde me va mostrando, en una función, la información en el ListView. Ahora mismo lo tengo así:
Código:

void __fastcall Thread::Mostrarlineas()
{
 TListItem* item = Form1->ListView->Items->Add();
 item->Caption = cadena1;
 item->SubItems->Add(cadena2);
 item->SubItems->Add(cadena3);
}

Ahora agrego el código siguiente:

Código:

void __fastcall Thread::Mostrarlineas()
{
 TListItem* item = Form1->ListView->Items->Add();
 
//agrego otro objeto item
 TListItem* dataitem = Form1->ListView->Items->Add();
 dataitem->Caption = cadena2; //cadena2 indica el protocolo(UDP,TCP..)
 if (dataitem->Caption == "TCP")
 {
  dataitem->Data = Pointer(0);
 }
else if (dataitem->Caption == "UDP")
 {
  dataitem->Data = Pointer(1);
 }
else
 {
  dataitem->Data = Pointer(2);
 }

 item->Caption = cadena1;
 item->SubItems->Add(cadena2);
 item->SubItems->Add(cadena3);
}

No se si esto es correcto, que está haciendo el nuevo código introducido?

Gracias.

maeyanes 09-07-2008 21:47:34

Hola...

Lo que tienes que hacer es:

Código:

void __fastcall Thread::Mostrarlineas()
{
  TListItem* item = Form1->ListView->Items->Add();
  item->Caption = cadena1;
  item->SubItems->Add(cadena2);
  item->SubItems->Add(cadena3);
  // Aquí el código:
  if (item->Caption == "TCP")
  {
    item-Data = 0;
  }
  else if (item->Caption == "UDP")
  {
    item->Data = 1;
  }
  else
  {
    item->Data = 2;
  }
}

Ahora, aquí estoy suponiendo que item->Caption tiene como valor el nombre del protocolo, si no es así, solo tienes que cambiar las comparaciones en los if...

También toma en cuenta que item->Data es una propiedad de tipo Pointer, esto al menos en Delphi, en C++ no se como se trate. También la asignación de los datos a item->Data puede que esté erronea, ya que C++ no es mi fuerte.

Una vez que logres esto, el códido en el evento OnCustomDraw del TListView puede ser una estructura switch..case sobre la propiedad item->Data...


Espero te sirva...


Saludos...

Ziara 11-07-2008 18:36:14

Hola de nuevo,

entonces si mi columna es la tercera me quedaría así:

Código:

void __fastcall Thread::Mostrarlineas()
{
 TListItem *item = Form1->ListView->Items->Add();
 item->Caption = cadena1;
 item->Caption = Add(cadena2);
 item->Caption = Add(cadena3);
//codigo nuevo
if (item->SubItems->Strings[2] == "TCP")
{
  item->Data = 0;
}
else if (item->SubItems->Strings[2] == "UDP")
{
  item->Data = 1;
}
else
{
  item->Data = 2;
 }

}

Se usa strings[] para concretar la columna no? si entre corchetes escribo 2 me estoy refiriendo a la columna nº3?

Cuando compilo me saca, el builder me saca un error:

no puede convertir un int en un *void

ya que item->data devuelve un *void y estoy asignadole un int.

Había pensando crear una variable para recoger el contenido de item->Data
algo como:

Código:

item->Data = var
pero var tiene que ser un variable que no devuelva nada y no sé qué tipo de variable usar para declarar var.

también había pensado en convertir item->Data en un int:

Código:

int var;
int (item->Data) = var;

pero esto me da el siguiente error:

No se puede modificar un objeto constante.

Hay alguna alternativa?

Gracias.

Ziara 05-08-2008 18:18:12

Muy buenas!

Alguien le puede echar un vistazo a este hilo plisss, que se me quedó la duda sin resolver :confused:. Y nu se porqué nu me sale...

Gracias de antemano!

roman 05-08-2008 18:40:24

A ver, según yo, item->Data es un apuntador a void para permitir que apunte a lo que necesitemos y bastaría hacer el moldeo:

Código:

(int *) item->Data = 84;
// Saludos

Ziara 05-08-2008 19:12:47

Hola!

Agradezco que hayas contestado tan rápido!

Lo he probado, y al compilar me da el error:

Lvalue required

Esto es algo de que la parte Izquierda de la asignación
(int *) item->Data = 1;
es una constante o algo así... pero no lo entiendo...?

Saludos y gracias.

escafandra 06-08-2008 16:48:40

Ziara, el problema es que item->Data es un puntero de tipo void* como te apuntó roman.

No le puedes asignar un entero o constante
Código:

item->Data = 1; // Error
Te dará error. Asígnale un puntero.
Por ejemplo: asociar a Data una variable hipotética llamada Hipotesis, del tipo que sea.

Código:

item->Data  = (void*)&Hipotesis; // encuentro el puntero y lo convierto a void*
Esto no te dará un error.

Saludos.


La franja horaria es GMT +2. Ahora son las 04:11:43.

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