PDA

Ver la Versión Completa : deshabilitar y habilitar evento onClick de un tcheckbox


marctonyus
28-07-2005, 16:50:01
HOla a todos, esa es mi pregunta. resulta que cuando pongo en false el checked del checkbox desde el código, se dispara su evento onClick, el cual quiero que se dispare solo cuando el usuario haga click manualmente. Alguna sugerencia?
Por toda ayuda muchas gracias

dec
28-07-2005, 17:07:51
Hola,

Se me ocurre algo así:


procedure TForm1.Button1Click(Sender: TObject);
var
copiaEvento: TNotifyEvent;
begin
// Guardamos el evento OnClick
copiaEvento := CheckBox1.OnClick;
// Quitamos el evento temporalmente
CheckBox1.OnClick := nil;

// Esto ya no disparará el evento OnClick
CheckBox1.Checked := not CheckBox1.Checked;

// Dejamos las cosas como estaban
CheckBox1.OnClick := copiaEvento;
end;

yusnerqui
28-07-2005, 18:18:29
Bueno, y si tenemos en cuenta que el evento click del check está dentro de tu código podriamos simplemnte:


procedure TForm1.Button1Click(Sender: TObject);
begin
// Quitamos el evento temporalmente
CheckBox1.OnClick :=nil;

// Esto ya no disparará el evento OnClick
CheckBox1.Checked :=not CheckBox1.Checked;

// Dejamos las cosas como estaban
CheckBox1.OnClick := CheckBox1Click;
end;


Saludos

dec
28-07-2005, 18:23:35
Hola,

Gracias yusnerqui.

marctonyus
28-07-2005, 21:41:53
muchas gracias a dec y yusnerqui

Chente(rMan)
22-08-2005, 22:11:40
Que tal, como le podría hacer para aplicarlo a n CheckBox, por ejemplo, tengo 30 CheckBox, si los deshabilito de un jalon y les cambio sus propiedades de checked, le ahago asi:


procedure TfrmForma.LimpiarCheckBox;
var
Check: TcheckBox;
I: Integer;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
// Check := Components[I] as TCheckBox;
Check := TCheckBox(Components[I]);
Check.OnClick := nil;
Check.Checked := False;
Check.Enabled := True;
end
end;


Después de esto hago mas cambios a los CheckBox, ahora bien, ya necesito activarlos de nuevo, como le hago?, le estado haciendo de estas formas:


procedure TfrmForma.HabilitarCheckBox;
var
Check: TcheckBox;
I: Integer;
Click : String;
Evento : TNotifyEvent;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check := TCheckBox(Components[I]);
Click := 'CheckBox' + IntToStr(I) + 'Click';
Check.OnClick := (Click as TNotifyEvent);
// CheckBox13.OnClick := CheckBox13Click;
end
end;


pero nada, ¿alguien que me pueda hechar la mano?.:confused:


Saludos. Vicente López.

Crandel
23-08-2005, 08:03:19
debes asignar el método OnClick a algun método del formulario que posea los mismos parámetros que el evento OnClick del CheckBox.

Asigna el mismo evento a todos y luego checkeas cual es.

Chente(rMan)
23-08-2005, 23:26:24
Creo que de esa manera no funciona:( , estamos hablando de 30 cb's, por eso quería optimizarlo.


Gracias.:)

dec
24-08-2005, 00:02:20
Hola,

Creo que hay un problema de diseño en tu aplicación, porque, verás, el tema tratado en este Hilo es algo muy particular, se trata de inhabilitar el evento "OnClick" de un "TCheckBox" de forma que se pueda cambiar programáticamente la propiedad "Checked" del mismo, sin que se dispare el evento "OnClick".

Pero, de ahí, a hacer lo propio con 30 "TCheckBox"... ¿realmente te hace falta? ¿No bastaría con habilitarlos/deshabilitarlos mediante su propiedad "Enabled"? Tú mismo dices lo siguiente:


(...) tengo 30 CheckBox, si los deshabilito de un jalon y les cambio sus propiedades de checked (...)

Pues bien, para habilitarlos/deshabilitarlos basta con recorrer los componentes y dar el valor que corresponda a su propiedad "Enabled". Pero si ya los deshabilitaste, ¿qué sentido tiene quitarles el método asociado a su evento "OnClick"? ¡Si el usuario no podrá hacer uso de los mismos!

En fin, creo que lo tratado en este Hilo no tiene que ver con lo que precisas hacer tú en tu programa, porque, de ser así, podrías hacerlo sin problemas. Así pues, creo que deberías reconsiderar el diseño de tu aplicación, dicho mal, pero pronto.

Por otro lado lo que dice Crandel es correcto, es decir, lo que te propone es que asignes un método capaz de tratar con el evento "OnClick" de los "TCheckBox", pues de otro modo no funcionará el asunto como se espera: probablemente ni compile tu programa.

Si tú dices que eso no es posible, porque en tu caso son 30 los "TCheckBox" a utilizar... piensa que servir, lo que se dice servir, sirve: no hay ningún problema en que un método esté asociado a los eventos que te sean menester y luego en el mismo discriminar qué hay que hacer en función de quién sea el objeto que disparara el evento, que a su vez ejecutó el método en cuestión.

En fin. No me enrollo más. Si das algún dato sobre lo que pretendes hacer tal vez se te pueda echar una mano, pero, creo que has pensado que es algo bueno hacer lo que se ha comentado en este Hilo y has decidido hacerlo en tu programa, sin contar que lo "bueno" también es algo particular, que, probablemente, no sea adaptable así sin más a tu aplicación.

Chente(rMan)
24-08-2005, 17:34:35
Tienes razón, creo que no me explique bien, pero como el titulo del post decia Deshabilitar y habilitar el onclick de un CheckBox, asumi que se entería;) , ahi estuvo mi error, "mia culpa":o , ok. lo interare otra vez, tengo 30 ChekBox:

CheckBox1
.
.
CheckBox30

cada uno de ellos tiene codigo diferente en su evento onclick.

Cuando yo hago una busqueda sobre uno de mis reportes, la propiedad checked de estos CheckBox debe cambiar segun lo criterios que defino en mi busqueda, entonces, ya que tengo los resultados de mis busquedas, me preparo a cambiar la propiedad checked de los cb's, para ello, pongo a todos en false a su propiedad checked.


procedure TfrmForma.LimpiarCheckBox;
var Check: TcheckBox;
I: Integer;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check := TCheckBox(Components[I]);
Check.Checked := False;
end;
end;


Con esto se dispara el evento OnClick de todos los cb's. Para ello necesito deshabilitar el onclick de estos. por lo tanto hago esto.


procedure TfrmForma.LimpiarCheckBox;
var Check: TcheckBox;
I: Integer;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check := TCheckBox(Components[I]);
Check.OnClick := nil;
Check.Checked := False;
end;
end;


Con esto logro que no se ejecute el OnClick, pero tengo entendido que debo de copiar el evento, como le puedo hacer para no tener que declarar 30 variables, uno para cada CheckBox.


procedure TfrmForma.LimpiarCheckBox;
var Check: TcheckBox;
I: Integer;
copiaEvento: TNotifyEvent;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check := TCheckBox(Components[I]);
copiaEvento := Check.OnClick //aqui es donde no se como...
Check.OnClick := nil;
Check.Checked := False;
end;
end;


para que despues de todas las validaciones que le hago al programa pueda voler a asignarle su evento a cada uno de ellos, algo asi.


procedure TfrmForma.LimpiarCheckBox;
var Check: TcheckBox;
I: Integer;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check := TCheckBox(Components[I]);
Check.OnClick := copiaEvento //y aqui regresarle su evento.
end;
end;



Espero que me puedan ayudar y gracias por contestar.:)


Saludos.

Vicente López.

Crandel
24-08-2005, 18:43:07
Aclaraste un poco mas pero no tanto,

queres ejecutar el mismo evento OnClick para todos los checkBox's o queres uno para cada uno?

Chente(rMan)
24-08-2005, 18:58:18
Uno para cada uno.

Cada CheckBox tiene su evento onclick, entonces tendria que grabar cada evento en una variable diferente para después regresarlelos.

ejemplo:


var Check: TcheckBox;
I: Integer;
copiaEvento1, copiaEvento2 ..... copiaEvento30: TNotifyEvent;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check := TCheckBox(Components[I]);
copiaEvento1 := Check.OnClick //aqui es donde no se como...
// copiaEvento {como irle cambiando los numeros} := Check.OnClick
Check.OnClick := nil;
Check.Checked := False;
end;



y de regreso pues lo mismo.:(

Saludos.

Vicente López.

Lepe
24-08-2005, 19:10:32
TForm1 = class(Tform)
private
Copias : array [1..30] of TNotifyEvent;

...
end;

var Check:Tcheckbox;
I: Integer;
contador:integer;
begin
contador := 0;
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check:= TCheckbox(Components[i]);
inc(contador);
copias[contador] := check.Onclick;

Check.OnClick := nil;
Check.Checked := False;
end;


al regresar los eventos funciona exactamente igual, siempre y cuando no agregues Checkboxes en tiempo de ejecución entre un guardado y una restauración.

Para restaurarlo, es ese mismo bucle pero usando:

check.Onclick := copias[contador]
y eliminando las 2 lineas siguientes.

Un saludo

Chente(rMan)
24-08-2005, 20:09:39
:) Genial Lepe, un arreglo, lo intentare y te aviso.


Editado: :D :) Listo, esta funcionando a la perfeción. Gracias a todos...



Saludos.

Vicente López.

Lepe
24-08-2005, 21:04:03
Edito: jajaja, ahora que está todo listo llego yo a rematarlo :D :D

Despues de todo el rollo, he creado un TcheckBox que no tiene ese comportamiento. Ha sido más facil de lo que creía. Os dejo la unidad.


unit CheckBoxNoClick;

interface

uses
Windows, Messages, SysUtils, Classes, Controls, StdCtrls;

type
TCheckBoxNoClick = class(tcheckBox)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
procedure SetChecked(Value:Boolean);
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Standard', [TCheckBoxNoClick]);
end;

{ TCheckBoxNoClick }

procedure TCheckBoxNoClick.SetChecked(Value: Boolean);
begin
try
clicksdisabled := True;
inherited;
finally
ClicksDisabled:= False;
end;
end;
end.


Cuando se quiera por código modificar el checked, se llama a SetChecked, que tiene el truco de inhabilitar el evento Click.

Saludos

Chente(rMan)
25-08-2005, 22:35:35
Que tal Lepe, pues te cuento que todavia no he probado la unidad, porque estoy algon intrigado con esto.


te cuento, es te es el procedimiento que me inhabilita los clicks de los checkBox...


procedure TfrmExpediente.LimpiarCheckBox; //Limpia los checkBox y Deshabilita el click...
var
Check: TcheckBox;
I, j: Integer;
begin
j := 0;
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBox then
begin
Check := TCheckBox(Components[I]);
inc(j);
CopiarEvento[j] := Check.OnClick;
Check.OnClick := nil;
Check.Checked := False;
Check.Enabled := True;
end;
end;


despues de que mando llamar este procedimiento, me dispongo a marcar los check Box que deben estar prendido segun unas condiciones, tomadas de una sentencia que ejecuto, pero ahora resulta que la sentencia me arroja 0 resultados, esta muy raro, ¿no cree?, ¿que podra estar sucediendo?:eek: .

Edito:
Ya instale la unidad, ya realize unas pruebas y no le entiendo, se supone que me deshabilita los click's ¿cierto?, este es el código que puse.


procedure TfrmExpediente.LimpiarCheckBox;
var I: Integer;
begin
for I := 0 to ComponentCount - 1 do
if Components[I] is TCheckBoxNoClick then begin
Check := TCheckBoxNoClick(Components[I]);
Check.SetChecked(False);
Check.Checked := False;
Check.Enabled := True;
end;


y después pongo CheckBoxNoClick1.Checked := True; y si me ejecuta el click.

Saludos.

Chente(rMan)
25-08-2005, 23:59:41
que tal, creo que al fin quedo solucionado, muy bueno por cierto, encontre este artículo.


http://www.delphi3000.com/articles/article_4298.asp?SK=checkbox


:D

Saludos.

Vicente López.

roman
26-08-2005, 01:04:26
http://www.delphi3000.com/articles/article_4298.asp?SK=checkbox


¡Vaya que hay gente complicada! :D

En el formulario donde uses tus CheckBox coloca esto antes de la declaración del formulario:



type
TCheckBox = class(StdCtrls.TCheckBox)
public
constructor Create(AOwner: TComponent); override;
end;


e implementa este constructor así:



constructor TCheckBox.Create(AOwner: TComponent);
begin
inherited;
ClicksDisabled := true;
end;


Eso es todo. Los CheckBox no dispararán el evento OnClick cuando se asigne Checked por código.

// Saludos

dec
26-08-2005, 01:52:17
Hola,

Una pregunta obligada, si se sigue el tema de este Hilo desde un principio: ¿cómo podría volverse a habilitar el Click programáticamente según tu propuesta roman? Tal vez ya no tenga mucho sentido hacerlo, puesto que no se quiera, pero, repito que sigo en la pregunta el tema de este Hilo.

roman
26-08-2005, 02:08:04
¿cómo podría volverse a habilitar el Click programáticamente según tu propuesta roman?

CheckBox1.ClicksDisabled := false;

// Saludos

dec
26-08-2005, 02:24:39
Hola,

Hombre, roman, si preguntaba es porque esa instrucción que refieres no me funciona (no sé porqué)...

Me dice aquello de "Undeclared identifier: 'ClicksDisabled'"...

Actualización: Está bien. Si hago uso de la interposición de la clase "TCheckBox" entonces no hay problema en usar la instrucción de marras.

roman
26-08-2005, 05:10:16
Está bien. Si hago uso de la interposición de la clase "TCheckBox" entonces no hay problema en usar la instrucción de marras.


¿Interposición? ¿Qué es eso?

ClicksDisabled es una propiedad protegida en TCheckBox, pero recordemos la accesibilidad de propiedades y métodos protegidos:


Accessible to code in the unit(s) where the class and its descendants are defined.


Como en la unidad del formulario TCheckBox es un descendiente de StdCtrls.TCheckBox, tal propiedad puede accederse libremente.

// Saludos

dec
26-08-2005, 06:19:15
Hola,

Sin duda no supe decir lo que quería decir. Muchas gracias roman.

roman
26-08-2005, 06:21:51
Sin duda no supe decir lo que quería decir

¿y qué es lo que querías decir? :confused:

¿Te funcionó o no?

// Saludos

dec
26-08-2005, 06:42:56
Hola,

Lo que quería decir (a ver si me sale ahora) es lo siguiente. Si yo no hago uso de la clase ("TCheckBox") interpuesta antes de la declaración del tipo del formulario, no puedo acceder a la propiedad "ClicksDisabled". Pero, como dije antes:


Actualización: Está bien. Si hago uso de la interposición de la clase "TCheckBox" entonces no hay problema en usar la instrucción de marras.

Si hago uso de la clase interpuesta tal y como proponías entonces puedo acceder a la propiedad "ClicksDisabled" sin problemas. Si ahora resulta que no es tanto porque se hiciera uso de la clase interpuesta, sino que se trata de lo que dices:


Como en la unidad del formulario TCheckBox es un descendiente de StdCtrls.TCheckBox, tal propiedad puede accederse libremente.

... porque, según Delphi:


Accessible to code in the unit(s) where the class and its descendants are defined.

Y sí, roman, ya sí puedo, como digo, hacer uso de la propiedad "ClicksDisabled", esto es, por lo que has comentado. Así que otra vez he vuelto a confundirme, puesto que no podía acceder a dicha propiedad no tanto por hacer o no hacer uso de la clase interpuesta, sino por lo que se refiere arriba que dice la ayuda de Delphi y tú transcribiste oportunamente.

(Esto si no es que puedo acceder a dicha propiedad precisamente por haber "redeclarado" la clase "TCheckBox", pues de otro modo acaso no fuera posible, de hecho no es posible si no lo hago así, como ya dije más arriba)

Crandel
26-08-2005, 07:17:37
Cuantas vueltas para explicar algo tan simple :eek:

ClicksDisabled esta declarado en la clase TButtonControl como una propiedad protected (protegida), por lo que sólo puede ser accedida desde la misma clase o sus descendientes.

Hay varias formas de poder acceder a ella

como lo hizo Lepe (http://www.clubdelphi.com/foros/showpost.php?p=102724&postcount=15), creando un nuevo componente que agrega una nueva propiedad para poder modificarlo.

Como lo hizo roman (http://www.clubdelphi.com/foros/showpost.php?p=102951&postcount=18), redefieniendo la clase y desabilitando directamente la propiedad, pero lo bueno es que no hay instalar ningún componente :).

y ahora para resumir doy la mia


TCheckBox = class(StdCtrls.TCheckBox)
public
property ClicksDisabled;
end;

simplemente hago pública la propiedad y ahora que cada uno la cambie a su antojo cuando quiera :D y como quiera, sin tener que instalar nada. Eso si debe estar antes de la declaración del formulario (igual que el de roman).

Si quieren crear un componente que ya lo tenga, para no tener que agregar este código en cada proyecto, cambian el public por published, cambian el nombre de la clase y lo registran.

Espero no haber liado más :p

roman
26-08-2005, 07:28:44
TCheckBox = class(StdCtrls.TCheckBox)
public
property ClicksDisabled;
end;



Je, je. Esto fue lo primero que pensé. Pero tiene un ligero inconveniente, al menos tomando en cuenta lo que originó este hilo.

Creo (porque el hilo es ya muy largo y no pretendo revisarlo desde el principio), que el deshabilitar los clicks se requiere para 30 checkboxes y de ahí que pensaron lo de un ciclo que los recorriera todos.

Haciendo que el constructor desactive los clicks se olvida uno del ciclo y de tener que hacerlo individualmente para cada control.

// Saludos

dec
26-08-2005, 07:39:48
Hola,

Pues al comenzar este Hilo el tema era cómo deshabilitar el evento "OnClick" de un solo "TCheckBox"... porque cuando se cambiaba la propiedad "Checked" de este programáticamente se disparaba dicho evento "OnClick", sin que se pretendiera tal cosa... el objetivo era hacer lo dicho y poder después recuperar el evento "OnClick" también programáticamente...

¡La cosa se fue un tanto de madre! ¿Verdad? ;)

Crandel
26-08-2005, 07:45:07
con esta cantidad de mensajes, de que estamos hablando? que queremos resolver? :confused: :confused: :D :D

dec
26-08-2005, 07:54:16
Hola,


con esta cantidad de mensajes, de que estamos hablando? que queremos resolver? :confused: :confused: :D :D

Bueno... si aquello de que no hay libro malo (que dice Miguel de Cervantes) se puede aplicar a los Hilos de un foro, es de suponer que algo se saque en claro. Sin embargo a mí personalmente no me disgusta que se traten temas separados en Hilos separados. Creo que beneficia al conjunto de usuarios. ¡Y no digo más! ;)

Ohcan
26-08-2005, 09:10:59
Vaya, precisamente ayer estuve leyendo un artículo de Ian Marteens sobre Clases Interpuestas:
http://www.marteens.com/trick46.htm
Aquí os dejo el link.

Saludos.

Lepe
26-08-2005, 11:40:00
Vaya, me descuido un poco y se monta un pollo :D

En El Checkbox que yo propuse, para hacer que se dispare el Onclick por código, usamos Checkbox.Checked := true /false

Cuando no queremos que se dispare el evento, simplemente usamos checkbox.SetChecked(true/false)

Y no tiene más historia.

Un saludo

FGarcia
07-12-2007, 22:08:17
Hola!

Aqui reviviendo este hilo. A ver no entendi. Estoy tratando de implementar el codigo de Roman:

unit UGeneralDatos;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, DBCtrls, Grids, DBGrids, ComCtrls, StdCtrls, Buttons,
DateUtils;

{Redefinimos el componente TCheckBox para evitar el evento OnClick}
type
TCheckBox = class(StdCtrls.TCheckBox)
public
constructor Create(AOwner: TComponent); override;
end;

{
constructor TCheckBox.Create(AOwner: TComponent);
begin
inherited;
ClicksDisabled := true;
end;
}

type
TfrmGDatos = class(TForm)
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
CheckBox3: TCheckBox;
CheckBox4: TCheckBox;
CheckBox5: TCheckBox;
CheckBox6: TCheckBox;
CheckBox7: TCheckBox;
CheckBox8: TCheckBox;
StringGrid1: TStringGrid;
procedure RadioGroup1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure BitBtn1Click(Sender: TObject);
procedure bbtnOKClick(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
procedure CheckBox5Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;

var
frmGDatos: TfrmGDatos;

implementation

uses UCnx, UHoraFecha, UVarios;

{$R *.dfm}

{Definimos el constructor del TCheckBox sin evento OnClick}
constructor TCheckBox.Create(AOwner: TComponent);
begin
inherited;
ClicksDisabled := true;
end;

procedure TfrmGDatos.FormCreate(Sender: TObject);
begin

checkbox1.Checked := true;
checkbox2.Checked := true;
checkbox3.Checked := false;
checkbox4.Checked := false;
checkbox5.Checked := false;
checkbox6.Checked := false;
checkbox7.Checked := true;
checkbox8.Checked := true;
end;



La pregunta: ¿esta correcto donde implemente el constructor?
La duda: Se sigue comportando igual, el evento OnClick se dispara de todos modos. ¿Donde me perdi?

jachguate
07-12-2007, 23:24:36
¿Esto compila?

NO veo donde está declarada la clase TCheckBox... ni creo que tus componentes sean de esa nuev aclase... ¿me equivoco?

FGarcia
08-12-2007, 14:34:19
Compila perfectamente, no registra error ni lanza algun aviso, solo que el comportamiento no es el que segun el incio del hilo menciona: Evitar el evento OnClick al asignar la propiedad checked por codigo.

p.d. El codigo no esta completo solo puse lo relevante a la redeclaracion del checkbox.

Lepe
08-12-2007, 19:50:07
Prueba a instalar mi componente, dicho en el mensaje nº 15 y después me comentas ;).

No voy a mirar las otras formas, porque hay varias, lo cierto, es que mi CheckboxNoclick si funciona porque lo he utilizado en algunos proyectos.

Las demás opiniones, no sé, no las he probado.

Con Gexperts.org no tendrás problemas en cambiar todos los checkbox por TcheckboxNoClick.

Creo recordar vagamente que había problemas colaterales al dejar ClicksDisabled a true.

Saludos

FGarcia
08-12-2007, 20:20:17
Gracias !!

Voy a probarlo y despues comento.

P.D. Probado, hasta el momento no he encontrado ningun efecto colateral.