Here's the code I'm working with.
procedure MarkOrClearAll(CListBox: TCheckListBox; CheckOrClear: Boolean);
var
Ctr: ShortInt;
begin
for Ctr := 0 to (CListBox.Items.Count - 1) do
CListBox.Checked[Ctr] := CheckOrClear;
end;
procedure TForm1.btnWWGridEventsMarkAllClick(Sender: TObject);
begin
MarkOrClearAll((Sender as TCheckListBox), True); // Dies here at runtime
with "Invalid class typecast"
end;
procedure TForm1.btnWWGridEventsClearAllClick(Sender: TObject);
begin
MarkOrClearAll((Sender as TCheckListBox), False); // Dies here at runtime
with "Invalid class typecast"
end;
Can anyone help?
TIA,
Karl Perry
I'd probably use the Tag property of the buttons to determine which
CheckListBox the user wants to work on. For example, all the buttons
controlling CheckListBox1 would have the tag set to 1.
Then pass that to the function instead:
procedure TForm1.btnWWGridEventsMarkAllClick(Sender: TObject);
begin
with Sender as TButton do
MarkOrClearAll(Tag, True);
end;
procedure MarkOrClearAll(Tag: Integer; CheckOrClear: Boolean);
var
Ctr: ShortInt;
lb: TCheckListBox;
begin
case Tag of
0: lb := CListBox0;
1: lb := CListBox1;
2: lb := CListBox2;
end;
for Ctr := 0 to lb.Items.Count-1 do
lb.Checked[Ctr] := CheckOrClear;
end;
That's just one way to do it...
btw: CListBox for a name? Damn C++ programmers =)
ShaneB
In the button OnClick event handlers, Sender is the button that was
pressed, not the checklist box.
Assuming WWGridEvents is the name of the checklist box, change the
OnClick code to:
MarkOrClearAll(WWGridEvents, ...
HTH,
Chris.
-------------
C.R. Timmons Consulting, Inc.
http://www.crtimmonsinc.com/
> btw: CListBox for a name? Damn C++ programmers =)
Hey! (<g>) I came over from Clipper, where there was no such thing as
variable "types." I adopted Hungarian notation there as a sanity measure -
it was the only way I could be sure, when for example receiving a parameter
to a function, of a variable's type. It helped me many times to remember,
"hey, dummy, this is supposed to be a logical type variable - not a
numeric."
CListBox in this case is just shorthand for "CheckListBox". I'm trying to
break out of Hungarian.
Thanks for the explanation of the dumb thing I was doing. I realize now
that I'm actually pressing a button that is INDEPENDENT of the checklistbox.
Karl
ahh,,,I didn't think of that :)
ShaneB
OK, that would work. However, this kind of thing kind of makes my skin
crawl. In a simple app such as what I'm working on today, I could easily
add a new CASE in the one or two different support functions
(MarkOrClearAll), but in a complex app, having to manage perhaps dozens of
these constructs, which just continue to grow, becomes unwieldy.
I'd prefer to make the EventsMarkAllClick function smart enough to figure
out the CheckListBox control, then just pass that to the MarkOrClearAll
function. That way, I can use the same event handler for all such buttons,
and I never have to change ANY code.
This app has several TGroupBoxes, each with a TCheckListBox, an All button
and a None button. I'd like to have the All button event handler iterate
through the TGroupBox control's child controls until it finds the
TCheckListBox, then stuff that into a call to MarkOrClearAll. But with my
limited (so far) knowledge of Delphi, I don't know how to manipulate all the
heirarchy properties etc.
Here's what I've tried so far:
procedure TForm1.btnWWGridEventsMarkAllClick(Sender: TObject);
var
Ctr: Integer;
MarkControl : TCheckListBox;
ParentCtrlCt: Integer;
begin
ParentCtrlCt := Parent.ControlCount; // Access violation here
for Ctr := 0 to (ParentCtrlCt - 1) do
if (Parent.Components[Ctr] is TCheckListBox) then
begin
MarkControl := Parent.Components[Ctr];
MarkOrClearAll(MarkControl, True);
break; // out of the loop
end;
end;
When I run the app, the debugger says that the value of Parent is nil. I
don't understand what I'm doing wrong.
Can you (or anyone else) help me with this?
Thanks,
Karl
The Parent you are using is the Parent of the Form...not of the button. You
didn't specify the button's parent...so Delphi assumes you're talking about
the form which also has a Parent property (if it didn't, you'd get a
compiler error).
Why is Parent nil?
In the help file under TForm.Parent it says:
"Use the Parent property to embed the form in another control (usually
another form). Changing the Parent property moves the form to a new
container.
Many forms do not have a Parent. For example, forms that appear directly on
the desktop have Parent set to nil."
Your form must not have a Parent if it's nil...
Also, I believe you want to use the Controls[] property and not the
Components[] property. The Controls property is used for figuring out
Parenting...the latter is for Ownership. A control's Owner is not
necessarily it's Parent.
Assuming the button is owned by the GroupBox, you can do something like
(untested cause I'm lazy today):
procedure TForm1.btnWWGridEventsMarkAllClick(Sender: TObject);
var
Ctr: Integer;
MarkControl : TCheckListBox;
begin
with Sender as TButton do
begin
for Ctr := 0 to Parent.ControlCount do
if (Parent.Controls[Ctr] is TCheckListBox) then
begin
MarkControl := Parent.Controls[Ctr];
MarkOrClearAll(MarkControl, True);
break; // out of the loop
end;
end;
end;
If that doesn't work, let me know and I'll throw a project together and
figure it out =)
HTH,
ShaneB
Karl Perry wrote nonsense. I finally made it work, if anyone's interested.
It's even down to a single function encompassing both 'Check' and 'Uncheck':
procedure TForm1.btnWWGridEventsMarkButtonClick(Sender: TObject);
var
Ctr: Integer;
ListBoxItemsCtr: Integer;
StillLooking: Boolean;
begin
StillLooking := True;
Ctr := 0;
while StillLooking do
begin
if ((TButton(Sender).Parent.Controls[Ctr]) is TCheckListBox) then
begin
for ListBoxItemsCtr := 0 to
((TCheckListBox(TButton(Sender).Parent.Controls[Ctr])).Items.Count -
1) do
(TCheckListBox(TButton(Sender).Parent.Controls[Ctr])).Checked[ListBoxItemsCt
r] :=
(UpperCase(TButton(Sender).Caption) = '&ALL');
StillLooking := False;
end
else
begin
Ctr := Ctr + 1;
if Ctr > (TButton(Sender).Parent.ControlCount - 1) then
StillLooking := False;
end;
end;
end;
> If that doesn't work, let me know and I'll throw a project together and
> figure it out =)
Shane,
Thanks for the explanation. I'm still figuring out all of this Parent/Owner
stuff.
While I was waiting, I figured it out myself. I posted the code I figured
out about 30 seconds before downloading your explanation. And yes, I was
misusing Component instead of Parent. Everyone here in the office got a
chuckle as my head banged against the wall.
Karl
procedure CheckUncheckAll(Sender: TObject; Checked: Boolean);
var
Ctr: Integer;
i: Integer;
begin
if Sender is TButton then
with Sender as TButton do
begin
for Ctr := 0 to Parent.ControlCount do
if (Parent.Controls[Ctr] is TCheckListBox) then
begin
for i:=0 to CheckListbox1.Items.Count-1 do
CheckListBox1.Checked[i] := Checked;
Break; // you could remove this if you want to check
multiple TCheckListBoxs with a single button clic
end;
end;
end;
In each button's event handler simply forward the Sender and the checked
state to it....ie
CheckUncheckAll(Sender, True) // checks them all
BEAT THAT!
=)
ShaneB
hehe...just read that post, GOOD LUCK :)
ShaneB
> BEAT THAT!
Cool. What's an appropriate kudo? Howzis: "You insane, Shane!"
If you want to be REALLY helpful, go check out my latest post: "How to
capture name of event that called an event handler". I just put it up about
five minutes ago.
Thanks again,
Karl Perry
Don't miss my other post above (8:05 pm).
ShaneB