Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Asignar a tbitbtn evento en tiempo de ejecucion (https://www.clubdelphi.com/foros/showthread.php?t=75245)

richy08 08-08-2011 20:40:44

Asignar a tbitbtn evento en tiempo de ejecucion
 
buenas tardes compañeros les explico un poco lo que quiero hacer, con un query estoy poniendo en tiempo de ejecucion bitbtn por cada categoria que encuentro en una bd, a estos bitbtn creados en tiempo de ejecucion quiero asignarles un evento, pero dicho evento necesito que lleve como parametro el id (lo obtengo del query) de cada categoria para lo cual uso el siguiente codigo

Código Delphi [-]
       Left:=8;
       top:=8;
       Qry_Line.Close;
       Qry_Line.Open;
       Seleccion:=0;
       Seleccion:=Qry_Line.RecordCount;

       While ido
       begin
          boton := TBitBtn.Create(nil);
          boton.Name:='btb'+inttostr(Qry_Line.fieldbyname('idlinea').Value);
          boton.Hint:=Qry_Line.fieldbyname('descripcion').Value;
          boton.Left:= left;
          boton.Top:=8;
          boton.Width:=81;
          boton.Height:=57;
          boton.Parent:=Pnl_line;
          linea:= Qry_Line.fieldbyname('idlinea').AsInteger;
          boton.OnClick:=categoriallena(linea);

          if FileExists('C:\Proyectos Delphi\Zibarita TouchScreen\Image\'+inttostr(Qry_Line.fieldbyname('idlinea').Value)+'.bmp') then
          begin
            boton.Glyph.LoadFromFile('C:\Proyectos Delphi\Zibarita TouchScreen\Image\'+inttostr(Qry_Line.fieldbyname('idlinea').Value)+'.bmp');
            boton.Caption:='';
          end
          else
            boton.Caption:=Qry_Line.fieldbyname('idlinea').Value;



         Qry_Line.next;
         left:=left+86;
         i:=i+1;
       end;
      end;

pero no logro hacer que compile, el motivo de llevar el id de la categoria es por que al ejecutar un click sobre el boton quiero que en otro tpanel mostrar las diferentes sub categorias, alguien me podria indicar como ligarle correctamente el evento en tiempo de ejecucion, y como deberia ser la declaracion del procedure que se encargara de mostrar las sub categorias, ahora lo tengo asi

Código Delphi [-]
procedure TFrm_Main.categoriallena(x: integer);
begin
  showmessage(inttostr(x));

end;

gracias por cualquier comentario

ecfisa 08-08-2011 21:42:14

Hola richy08.

Cita:

quiero asignarles un evento, pero dicho evento necesito que lleve como parametro el id
Lamentablemente no podés hacerlo de ese modo.

Pero se me ocurren dos modos de obtener el valor ID en el evento OnClick del TBitBtn.
Uno del nombre que le asignas al TBitBtn (ya que incluís el ID) . Y el segundo, que creo más simple y seguro, asignando el valor ID a la propiedad Tag del BitBtn en la creación.

Ejemplo:
Código Delphi [-]
procedure TTuForm.BitBtnClick(Sender: TObject);
var
  Valor_id: Integer;
begin
  Valor_id:= StrToInt(Copy(TBitBtn(Sender).Name, 4, MaxInt));  // extraer valor  ID del nombre
  Valor_id:= TBitBtn(Sender).Tag; // extraer valor ID de Tag
  ShowMessage(IntToStr(Valor_id)); // o lo que hagas con el valor
  ...
end;

...
begin
  Left:=8;
  top:=8;
  Qry_Line.Close;
  Qry_Line.Open;
  Seleccion:=0;
  Seleccion:=Qry_Line.RecordCount;
  While ido
  begin
     boton := TBitBtn.Create(nil);
     boton.Name:='btb'+inttostr(Qry_Line.fieldbyname('idlinea').Value);
     boton.Hint:=Qry_Line.fieldbyname('descripcion').Value;
     boton.Left:= left;
     boton.Top:=8;
     boton.Width:=81;
     boton.Height:=57;
     boton.Tag:= Qry_Line.fieldbyname('idlinea').AsInteger; // Valor ID en Tag
     ...
     boton.OnClick:= BitBtnClick;
     ...

Saludos.

maeyanes 08-08-2011 21:45:37

Hola...

El detalle es que las propiedades que son eventos son de un tipo especial. En el caso del evento OnClick son del tipo TNotifyEvent el cual está declarado como:

Código Delphi [-]
type
  TNotifyEvent = procedure (Sender: TObject) of object;

Esto es, que a la propiedad OnClick solo le puedes asignar métodos de objeto con la misma firma que la declarada:

Código Delphi [-]
TMyForm = class(TForm)
  // Declaraciones de componentes y manejadores de eventos
private
  procedure DoOnClick(Sender: TObject);
  // ....
end;

implementation

procedure TMyForm.DoOnClick(Sender: TObject);
begin
  // Hacer algo
end;

// Asignar evento en tiempo de ejecución:
BitBtn.OnClick := DoOnClick;

Para lo que tu necesitas, podrías usar la propiedad Tag de los componentes. Esta propiedad es de tipo entero y bien podría almacenar el valor del ID.

Código Delphi [-]
while ido
  begin
    boton := TBitBtn.Create(nil);
    // inicializas propiedades
    linea := Qry_Line.fieldbyname('idlinea').AsInteger;
    boton.Tag := linea;
    boton.OnClick := DoOnClick;
    // demás código
end;

// Método DoOnClick;
procedure TMyForm.DoOnClick(Sender: TObject);
begin
  if Sender is TBitBtn then
  begin
    with TBitBtn(Sender) do
    begin
      if Tag = 1 then
        // ...
      else
        if Tag = 2 then
          // ...
    end
  end
end;

Esto es solo un ejemplo, pero podría ayudarte a resolver tu problema.



Saludos...

richy08 08-08-2011 23:11:52

gracias a los dos por sus consejos, probare para ver cual es la mejor forma de resolverlo


saludos

richy08 08-08-2011 23:40:09

ok ya lo probe y si funciona parcialmente, digo parcialmente por que al presionar el boton me muestra ya los sub menus pero no entiendo por que desaparecen los botones :confused: de linea al ser presionados el evento que mando llamar en el onclick es este

Código Delphi [-]
procedure TFrm_Main.DoOnClick(Sender: TObject);
var
i, seleccion : integer;
botonC : tbitbtn;
left, top: integer;
begin
  if Sender is TBitBtn then                                                           
  begin
    with TBitBtn(Sender) do
    begin
       Left:=15;
       top:=16;
       Qry_Categoria.Close;
       Qry_Categoria.ParamByName('idlinea').Value:=tag;
       Qry_Categoria.Open;
       i:=0;
       Seleccion:=0;
       Seleccion:=Qry_Categoria.RecordCount;

       While ido
       begin
          botonC := TBitBtn.Create(nil);
          botonC.Name:='btbc'+inttostr(Qry_Line.fieldbyname('idlinea').Value);
          botonC.Hint:=Qry_Categoria.fieldbyname('descripcion').Value;
          botonC.Left:= left;
          botonC.Top:=top;
          botonC.Width:=81;
          botonC.Height:=57;
          botonC.Parent:=Categoria;
      //    boton.OnClick:=;

          if FileExists('C:\Proyectos Delphi\Zibarita TouchScreen\Image\'+inttostr(Qry_Categoria.fieldbyname('idcat').Value)+'.bmp') then
          begin
            botonC.Glyph.LoadFromFile('C:\Proyectos Delphi\Zibarita TouchScreen\Image\'+inttostr(Qry_Categoria.fieldbyname('idcat').Value)+'.bmp');
            botonC.Caption:='';
          end
          else
            botonC.Caption:=Qry_Categoria.fieldbyname('idcat').Value;

         Qry_Categoria.next;
         top:=top+62;
         i:=i+1;
       end;
    end;
  end;
end;

alguna idea ??, mil gracias por su tiempo

corrijo no desaparecen se cambian de posicion :S

richy08 08-08-2011 23:47:32

ya encontre el detalle el codigo queda asi

Código Delphi [-]
procedure TFrm_Main.DoOnClick(Sender: TObject);
var
i, seleccion : integer;
botonC : tbitbtn;
left, top: integer;
begin
  if Sender is TBitBtn then                                                           
  begin
    with TBitBtn(Sender) do
    begin
       Qry_Categoria.Close;
       Qry_Categoria.ParamByName('idlinea').Value:=tag;
       Qry_Categoria.Open;
    end;

    
       Left:=15;
       top:=16;

       i:=0;
       Seleccion:=0;
       Seleccion:=Qry_Categoria.RecordCount;

       While ido
       begin
          botonC := TBitBtn.Create(nil);
          botonC.Name:='btbc'+inttostr(Qry_Line.fieldbyname('idlinea').Value);
          botonC.Hint:=Qry_Categoria.fieldbyname('descripcion').Value;
          botonC.Left:= left;
          botonC.Top:=top;
          botonC.Width:=81;
          botonC.Height:=57;
          botonC.Parent:=Categoria;
      //    boton.OnClick:=;

          if FileExists('C:\Proyectos Delphi\Zibarita TouchScreen\Image\'+inttostr(Qry_Categoria.fieldbyname('idcat').Value)+'.bmp') then
          begin
            botonC.Glyph.LoadFromFile('C:\Proyectos Delphi\Zibarita TouchScreen\Image\'+inttostr(Qry_Categoria.fieldbyname('idcat').Value)+'.bmp');
            botonC.Caption:='';
          end
          else
            botonC.Caption:=Qry_Categoria.fieldbyname('idcat').Value;

         Qry_Categoria.next;
         top:=top+62;
         i:=i+1;
       end;
  end;
end;



saludos

maeyanes 09-08-2011 01:22:40

Hola...

No se exactamente que deseas hacer, lo que si te puedo decir es que tu código está propenso a que tengas pérdidas de memoria (memory leak) al momento de cerrar la aplicación.

Si no vas a guardar referencias a los botones fuera del método DoOnClick, te recomiendo que uses TBitBtn.Create(Self), para que al cerrar el formulario este destruya todos esos botones al momento de destruirse.

Otro error que encuentro es que estás usando algunas variables con el mismo nombre de propiedades (Top, Left) y esto puede producirte varios errores lógicos.


Saludos...

richy08 09-08-2011 16:19:08

Cita:

Empezado por maeyanes (Mensaje 408853)
Hola...

No se exactamente que deseas hacer, lo que si te puedo decir es que tu código está propenso a que tengas pérdidas de memoria (memory leak) al momento de cerrar la aplicación.

Si no vas a guardar referencias a los botones fuera del método DoOnClick, te recomiendo que uses TBitBtn.Create(Self), para que al cerrar el formulario este destruya todos esos botones al momento de destruirse.

Otro error que encuentro es que estás usando algunas variables con el mismo nombre de propiedades (Top, Left) y esto puede producirte varios errores lógicos.


Saludos...

Hola maeyanes lo que intento hacer es una aplicacion que sirva para vender productos de mostrador pero en un touch screen, lo de crear botones es por la estructura que tienen la tablas en la bd, los primeros botones que muestros son los de la linea que a su ves es padre de categoria y esta es padre de subcategoria hasta llegar a los productos.

ok usare TBitBtn.Create(Self) no entiendo muy bien el por que, es la primera ves que me veo en la necesidad de crear componentes en tiempo de ejecucion, y sobre lo del nombre de las variables segun yo, si las declaro dentro de un procedure el valor solo se afecta dentro del mismo procedure no??, corrigeme por favor si dije alguna incoherencia


saludos y mil gracias por tus consejos


perdon ya entendi lo de las variables es mejor ponerles otro nombre, que no se parezca a propiedades de los objetos, otra pregunta crees que este codigo me genere algun problema lo uso cada que presiono un boton para limpiar el panel e incluir los nuevos botones

Código Delphi [-]
   for i:=Pnl_Pro.ControlCount -1 downto 0 do
    begin
      if Pnl_Pro.Controls[i] is Tbitbtn then
       Pnl_Pro.Controls[i].free;
    end;

maeyanes 09-08-2011 18:08:45

Hola...

Por lo poco que puedo ver de tu código, y sin saber que haces fuera de lo que nos enseñado, te puedo decir que tu aplicación corre peligro de consumir mucha memoria y luego de un buen tiempo de uso puede fallar con errores del tipo Out of Memory. Aparte, si no te consumes toda la memoria, al finalizar la aplicación esta no va a liberar toda la memoria que consumió. Ahora, el por que de esto que te comento:

Veo que creas varios TBitBtn, todos sin un owner (TBitBtn.Create(nil)), y estos los asignas a variables declaradas dentro del método donde se crean, esto es, esas variables dejarán de existir una vez salgas de ese método, haciendo que no haya forma que puedas referenciar esos TBitBtn más adelante y como estos no tienen dueño, al finalizar la aplicación tampoco se destruirán. Aunado a esto, cada que presionas un botón ya creado, creas una serie de botones usando la misma técnica y en ningún momento veo que elimines los botones creados anteriormente.

Una forma de resolver esto es asignándole un dueño a cada TBitBtn que se cree, es por eso que te comenté el uso de Self, que en el ámbito donde lo vas a usar, sería el formulario donde estás creando esos botones. Al ser el formulario el dueño de esos botones, al destruirse este, primero destruye todos los componentes que le pertenecen.

La recomendación que yo te doy, es usar algún tipo de lista para guardar las referencias a los botones que vayas creando y así los puedas eliminar apenas los dejes de usar. Aquí algo de código para aclarar la idea:

Código Delphi [-]
TMyForm = class(TForm)
  // Declaraciones de componentes en tiempo de diseño
private
  FBtnPadre: TComponentList;
  FBtnCategoria: TComponentList;
  FBtnSubCategoria: TComponentList;
  FBtnProducto: TComponentList;
public
  // ...
end;

implementation

// Evento OnCreate y OnDestroy del formulario:
procedure TMyForm.FormCreate(Sender: TObject);
begin
  FBtnPadre := TComponentList.Create;
  FBtnCategoria := TComponentList.Create;
  FBtnSubCategoria := TComponentList.Create;
  FBtnProducto := TComponentList.Create;
  // Algún otro código de inicialización
end;

procedure TMyForm.FormDestroy(Sender: TObject);
begin
  // Algún otro código de finalización
  FBtnPadre.Free;
  FBtnCategoria.Free;
  FBtnSubCategoria.Free;
  FBtnProducto.Free
end;

// Método donde creas los botones padre:
  // ...
  Btn := TBitBtn.Create(nil); // no se usa owner ya que la lista se encargará de esto
  // Asignamos propiedades
  FBtnPadre.Add(Btn);
// ...

// Método OnClick de los botones padre:
  // Primero verificamos si ya existen botones de categorías y eliminamos los que ya existen
  if FBtnCategoria.Count > 0 then
    FBtnCategoria.Clear;
  // Query que lee categorías...
  Btn := TBitBtn.Create(nil);
  // Asignamos propiedades
  FBtnCategoria.Add(Btn);
// ...

// Método OnClick de los botones de categorías:
  // Primero verificamos si ya existen botones de subcategorías
  if FBtnSubCategoria.Count > 0 then
    FBtnSubCategoria.Clear;
  // Query que lee subcategorias
  Btn := TBitBtn.Create(nil);
  // Asignamos propiedades
  FBtnSubCategoria.Add(Btn);
// ...

Ya con este código te debes de dar una idea de como hacer mejor las cosas...


Saludos...

richy08 09-08-2011 18:15:23

mil gracias maeyanes por la explicacion, :D si estaba un poco perdido y no estaba viendo todos los errores de memoria que estaba generando :o, y como este programa correra en un touch screen con poca memoria seria todo un lio y en pocas horas de usarlo seguro me llamarian para ver el por que del error

saludos.


La franja horaria es GMT +2. Ahora son las 08:18:21.

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