Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TCheckListBox and Invalid Type Cast

71 views
Skip to first unread message

Karl Perry

unread,
Aug 17, 2001, 4:36:09 PM8/17/01
to
I'm using several TCheckListBox components on my form, and want to create
two buttons for each checklist box: one to mark every item as Checked, the
other to clear every item's Checked status (All and None buttons). I'd like
to create a single procedure, MarkOrClearAll, to do the actual work of
checking or clearing the checkboxes. From the appropriate button on the
form, the 'OnClick' event procedure will call this function. However, I
can't figure out how to typecast the call to the MarkOrClearAll procedure.
I keep getting an "Invalid class typecast" exception at runtime.

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


ShaneB

unread,
Aug 17, 2001, 5:01:20 PM8/17/01
to
The Sender isn't a TCheckListBox, it's a TButton (presumably). You're
trying to convert an apple to an orange at runtime.

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

Chris R. Timmons

unread,
Aug 17, 2001, 5:18:03 PM8/17/01
to
Karl,

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/

Karl Perry

unread,
Aug 17, 2001, 5:24:46 PM8/17/01
to

"ShaneB" <stor...@bigfoot.com> wrote in message news:3b7d85c4_1@dnews...

> 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


ShaneB

unread,
Aug 17, 2001, 5:59:13 PM8/17/01
to
> CListBox in this case is just shorthand for "CheckListBox". I'm trying to
> break out of Hungarian.

ahh,,,I didn't think of that :)

ShaneB

Karl Perry

unread,
Aug 17, 2001, 6:15:51 PM8/17/01
to

"ShaneB" <stor...@bigfoot.com> wrote in message news:3b7d85c4_1@dnews...
> The Sender isn't a TCheckListBox, it's a TButton (presumably). You're
> trying to convert an apple to an orange at runtime.
>
> 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.
>

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


ShaneB

unread,
Aug 17, 2001, 7:35:34 PM8/17/01
to
First, your Parent problem:

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

unread,
Aug 17, 2001, 7:33:33 PM8/17/01
to

"Karl Perry" <kpe...@animalintelligence.com> wrote in message
news:3b7d986f$1_2@dnews...

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;

Karl Perry

unread,
Aug 17, 2001, 7:36:25 PM8/17/01
to

"ShaneB" <stor...@bigfoot.com> wrote in message news:3b7da9e9_1@dnews...

> 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


ShaneB

unread,
Aug 17, 2001, 8:05:26 PM8/17/01
to
Ok, now you got me going! Here's an improvement (tested) that's simpler,
safer, AND it handles checking as well as unchecking.

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

ShaneB

unread,
Aug 17, 2001, 8:28:24 PM8/17/01
to
"Karl Perry" <kpe...@animalintelligence.com> wrote in message
news:3b7db289$1_1@dnews...
> 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.

hehe...just read that post, GOOD LUCK :)

ShaneB

Karl Perry

unread,
Aug 17, 2001, 8:07:13 PM8/17/01
to

"ShaneB" <stor...@bigfoot.com> wrote in message news:3b7db0e9$1_2@dnews...

> Ok, now you got me going! Here's an improvement (tested) that's simpler,
> safer, AND it handles checking as well as unchecking.

> 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


ShaneB

unread,
Aug 17, 2001, 8:07:45 PM8/17/01
to
heheh

Don't miss my other post above (8:05 pm).

ShaneB

0 new messages