Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Cronómetro y listview (https://www.clubdelphi.com/foros/showthread.php?t=6967)

juanchi 29-01-2004 01:21:58

Cronómetro y listview
 
Hola amigos, tengo un problema cuando quiero iniciar un cronómetro en un listview porque quiero que al iniciarse un formulario este en cero, pero cuando aprieto un botón comience la cuenta, y lo que me pasa es que me da los minutos del cual se inició la aplicación al apretar el botón, y este no corre. Otra cosa como hago cuando llegue a tal minuto me cambie el valor de otra columna. Desde ya agradecido enormemente. :)

juanchi 02-02-2004 02:53:35

Hola, sigo con esto es que hago lo siguiente

var
inicio : TDateTime;

Procedure TForm1.Create(Sender : TOject);
var
item : TListItem;
begin
inicio := now;
item := ListView1.Add;
item.Caption := 'PC01';
item.SubItems.Add('Libre');
end;


Procedure TForm1.Timer1Timer(Sender : TOject);
var
item : TListItem;
begin
item.SubItems.Add(FormatDataTime('HH:mm:ss', Now - inicio);
end;

y me sale un error en tiempo de ejecución. Pero si agrego ListView1.Add en el evento OnTimer me da el tiempo en cada segundo

Lepe 02-02-2004 11:44:06

Código:

Procedure TForm1.Timer1Timer(Sender : TOject);
var
item : TListItem;
begin
item.SubItems.Add(FormatDataTime('HH:mm:ss', Now - inicio);
end;

Piensa que item: Tlistitem es una variable local, no está realmente creada en memoria, y es más, no está apuntando al ListView que deseas.

La solución, acceder desde el timer al ListView:
Código:

Procedure TForm1.Timer1Timer(Sender : TOject);
begin
  ListView.items[3].SubItems[0] := (FormatDataTime('hh:nn:ss', Now - inicio);
end;

Yo accedo a la fila 3, al primer subitems.

Por cierto, la cadena para formatear la hora, aunque es la más intuitiva, no es la correcta, para mostrar los minutos tienes que poner "nn".


Saludos

Lepe 02-02-2004 11:46:56

Cita:

Pero si agrego ListView1.Add en el evento OnTimer
Pregunta: ¿Realmente quieres añadir un SubElemento en cada segundo? ;)

juanchi 03-02-2004 16:28:44

Gracias por tu respuesta, pero te cuento que sigo teniendo el mismo error que sale que no puedo acceder a una dirección de memoria.

Lepe 04-02-2004 11:38:44

Código:

var i, subi:Integer;
begin
i:= 3;
subi:=0;
  if i < ListView1.Items.Count then
  begin
    if subi < ListView1.Items[i].SubItems.Count then
    begin
      ListView1.Items[i].SubItems[subi] := 'Ocupado'
    end
    else
      ShowMessage('no tiene subItems'); // crear el SubItem aqui ???
  end
  else
    ShowMessage ('Elemento no existe'); // crear el Elemento aqui ???

A ver si detectamos la "maldita" direccion :)

Por otra parte, en Listview1.columns debe haber definido al menos 2 columnas, ( la 0 y 1)

Saludos

juanchi 08-02-2004 23:17:02

Muchas gracias por tu respuesta :) . Te cuento que cuando me aparece la hora y hago click en otra parte del ListView, la hora se corta y aparece en donde hice click para seguir con el conteo. Otra cosa, como hago para que solo un subitem tome color ya que todos los subitems lo hacen. Te mando algo de código para que me puedas entender.

procedure TForm1.ListView1ColumnClick(Sender: TObject;
Column: TListColumn);
begin
nSortCol := Column.Index;
ListView1.AlphaSort;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
i : integer;
begin
if ListView1.Selected <> nil then
ListView1.Selected.SubItems[1] := FormatDateTime('hh:nn:ss', Now - inicio);
end;

procedure TForm1.Abrir1Click(Sender: TObject);
begin
inicio:=Now;
Timer1.Enabled := true;
end;

procedure TForm1.ListView1CustomDrawSubItem(Sender: TCustomListView;
Item: TListItem; SubItem: Integer; State: TCustomDrawState;
var DefaultDraw: Boolean);
var
i : integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
begin
if ListView1.Items.Item[i].SubItems[0] = 'Libre' then
ListView1.Canvas.Font.Color := RGB(0,120,0);
end;
end;

Muchas gracias. Saludos :)

Lepe 09-02-2004 11:52:35

Holas de nuevo :)

Cita:

Empezado por juanchi
hago click en otra parte del ListView, la hora se corta y aparece en donde hice click para seguir con el conteo.

De momento me surge una duda, se supone que la hora de inicio será distitnta para cada PC, por tanto, habría que guardarla en "algun sitio" .
Hay varias formas de hacerlo:
- Usando el objeto TObjectList. (vease ayuda de delphi ;))
- Usando una tabla en la que cada elemento es un registro con información asociada a cada PC.

Yo me quedaria con la primera opción. En cuanto a lo del timer:
Código:

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i : integer;
begin
  for i:=0 to pred(listview1.items.count) do
    if listview1.items[i].subItems[0] <>'Libre' then
      ListView1.items[i].SubItems[1] := FormatDateTime('hh:nn:ss', Now - DatosPc[i].HoraInicio);
end;

En cuanto a lo de pintar de color, la verdad, no tengo ni idea. Lo primero que me viene a la mente es que los Subitems, son de tipo Tstring, así que no tiene una propiedad Font asociada. Puede que alguien del foro pueda ayudarte.

Saludos

juanchi 12-02-2004 13:00:48

Hola :) , te cuento que para la hora tengo una tabla con intervalos de tiempo con valores enteros, y realizo lo siguiente:


procedure TForm1.Timer1Timer(Sender: TObject);
var
i : integer;
v : string;
tiempo : TDateTime;
begin
v := inttostr(Form4.TarifaHasta.AsInteger);
tiempo := strtotime(v);
for i:=0 to pred(listview1.items.count) do
if listview1.items[i].subItems[0] = 'Libre' then
ListView1.Selected.SubItems[1] := FormatDateTime('hh:nn:ss', now -tiempo );
end;

pero no me toma el valor de la tabla, voz que me recomendas. Hasta pronto y gracias por tu paciencia.

Saludos. :)

Lepe 13-02-2004 13:03:55

Cita:

te cuento que para la hora tengo una tabla con intervalos de tiempo con valores enteros
mmm, Usas Bases de datos para el resto del programa ?

Si Usas Bases de datos, es más facil crear un campo HoraInicio (de tipo Date) asociado a cada Pc

Si no Usas Bases de datos, acabo de mirar bien el tipo TlistItem y tiene una propiedad llamada Data aqui se puede guardar un puntero a cualquier cosa, así que puedes crearte un puntero a un registro y guardar ahí la hora de inicio de cada Pc.

Para que veas como va. crea un programa nuevo, metele un Listview, un Boton y un timer con Interval a 1 seg.

Este es mi codigo.
Código:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls, ExtCtrls;

type TInfo = record      // Tipo Informacion
        Hora : TDateTime;
end;
    TpTInfo = ^TInfo; // Tipo Puntero al tipo Informacion
type
  TForm1 = class(TForm)
    Button1: TButton;
    ListView1: TListView;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var H :TpTInfo;
begin
  with ListView1.items.Add do
  begin
    Caption := 'PC3';
    SubItems.Add('Ocupado');
    SubItems.Add('');
    New(H);
    H^.Hora:=Now;
    Data:= H;
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  hora:TDateTime;
  i : integer;
begin
    with ListView1 do
    for i:=0 to pred(items.count) do
      if items[i].subItems[0] <>'Libre' then
      begin
        if Assigned(Items[i].data) then  // me aseguro de que se ha creado el registro
        begin
          hora :=TpTinfo(Items[i].data)^.Hora;
          items[i].SubItems[1] := FormatDateTime('hh:nn:ss', Now - Hora );
        end;
      end;

end;

end.

El ejemplo consiste en que cada vez que pulsas el boton se crea un nuevo elemento y aprovecha la propiedad Data para meter la hora en un registro asociado a cada elemento del Listview. En el registro TInfo podrías guardar toda la información que necesitaras.

Eso si. Todo lo que almacenas en Data, eres tú el que has de liberarlo antes de borrar algun elemento del listview.

Saludos, y espero que alguno de estos métodos te sirva. :)
_________________________________________________
Sugerencia: escribir el codigo fuente entre [ code] y [ /code] al postearlo en el foro. (sin el espacio que hay despues del corchete [, es mas facil leerlo)

juanchi 16-02-2004 02:10:45

Hola :)
Si uso tablas en el programa, lo que escribiste me sirvió para el tiempo libre, y quiero hacer otra para el prepago, o sea tener en la tabla tiempos de 30, 60, una hora y media, etc, y seleccionar el tiempo adecuado.

Saludos. :)

Lepe 16-02-2004 11:48:34

No le veo mucho problema, añadiendo en el uses Dateutil, puedes acceder a esta funcion (al menos en delphi 6):
Código:

H^.HoraInicio:= now;
 H^.HoraFin:=incminute(H^.horainicio, Form4.TarifaHasta.AsInteger);

Para elegir la tarifa correcta, supongo que darás al usuario la opcion en pantalla, con un combo, un LookupCombo, no sé.....

Por cierto, me alegro que el código anterior te sirva para algo :)

Como te decia, antes de borrar un elemento del Listview, tienes que liberarlo con Dispose(TpTInfo(listview1.items[X].data)). Si hay elementos que no tienen el registro asociado, pues deberás hacer primero la comprobación de si ha sido creado o no.

Saludos

__cadetill 16-02-2004 12:16:44

Cita:

Empezado por Lepe
... añadiendo en el uses Dateutil ....

Sólo decir, antes de que pregunten, que esta unit pertenece a las RX Lib, por lo que si no las teneis instaladas, os dará un error de compilación

Lepe 16-02-2004 18:12:03

Cita:

Empezado por cadetill
Sólo decir, antes de que pregunten, que esta unit pertenece a las RX Lib, por lo que si no las teneis instaladas, os dará un error de compilación

Gracias por la aclaración. Ni yo mismo estaba al corriente :D

sodulaS :D

juanchi 17-02-2004 11:54:01

Hola de nuevo :) .
Te cuento que he intentado pero no consigo que los valores enteros de la grilla de un formulario en la cual tengo los tiempos, y al seleccionar uno que los pase al listview como un tiempo decreciente. Gracias.

Saludos. :)

Lepe 17-02-2004 14:00:20

Para el tema de la rejilla, es copiado literalmente de la ayuda de delphi, adaptandolo te puede servir:
Código:

var
  i, j: Integer;
  s: string;
begin
  if DBGrid1.SelectedRows.Count>0 then
    with DBGrid1.DataSource.DataSet do
      for i:=0 to DBGrid1.SelectedRows.Count-1 do
      begin
        GotoBookmark(pointer(DBGrid1.SelectedRows.Items[i]));
        for j := 0 to FieldCount-1 do
        begin

          if (j>0) then s:=s+', ';
          s:=s+Fields[j].AsString;
        end;
        Listbox1.Items.Add(s);
        s:= '';
      end;

Cita:

Empezado por juanchi
y al seleccionar uno que los pase al listview como un tiempo decreciente.

No sé si lo he entendido. Creo que quieres restarle X minutos a una hora determinada. Si dispones de las Rusas (RxLib) puedes usar la funcion que posteé antes, pasandole un nº negativo. Si no dispones de ella, tendrías que hacer un cálculo. Sabiendo que una fecha es un nº real, 32723,05671 y que 1 unidad corresponde a 1 dia de tiempo, puedes hacer tu mismo el cálculo para saber: 30 minutos cuantos dias son, y restar ese valor directamente a una fecha dada.

Ahora te toca pensar a ti un poquito ;)

Te aconsejo que te pares a estudiar un poquito el tema de las fechas en delphi, con 10 minutos peleandote, te aclarará muchas dudas.

ShowMessage(Formatdatetime('dd/mm/yyyy hh:nn:ss', now - MiValorDouble)

sodulaS :)


La franja horaria es GMT +2. Ahora son las 06:12: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