Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Array of TK::Checkbuttons not acting appropriately

by mikasue (Friar)
on Oct 02, 2006 at 01:29 UTC ( [id://575826]=perlquestion: print w/replies, xml ) Need Help??

mikasue has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monks, I am trying to display a checklist in a perl Tk program i'm writing. I am having trouble with the Tk::Checkbutton. When I use the following code the checkbuttons do not show up. If I make the arrays into single scalars the checkboxes show up but when I check 1 they all are checked because it's only 1 value for all. So I think I need an array to hold each checkbutton and an array to hold each checkbutton value.
Please tell me what i'm doing wrong. Thanks!
my $x = 1; #index for table rows my $t=0; #index for checkbuttons and values my @checkboxvalue; #array to hold the checkutton values for each chec +kbox my @checkbox; #array to hold the checkbuttons for each row foreach my $m (@unpaidbills) { $checkbox[$t]= $bill_table->Checkbutton(-variable=>\$checkboxvalue[ +$t]); $bill_table->put($x,0, $checkbox[$t]); $bill_table->put($x,1, $m->{bill_name}); $bill_table->put($x,2, "\$$m->{bill_amountdue}"); $bill_table->put($x,3, "$main::month\/$m->{bill_datedue}\/$mai +n::year"); $bill_table->put($x,4, "\$$m->{bill_amountpaid}"); $bill_table->put($x,5, $m->{bill_datepaid}); @paymethods = BPP::PAYMETHODS->retrieve($m->{bill_paymethod}); $bill_table->put($x,6, map{$_->{paymethod_desc}}@paymethods); my $paybill = $bill_table->Button(-text=>'Submit', -command=>sub{ if ($checkboxvalue[$t] == 1) +{ &BillPaymentScreen($m->{bill_name}, $m->{bill_amountdue}, $m->{bill_da +tedue}, $m->{bill_id}, $tltop) } else { print "checkbox not paid"} + }#end sub )->pack; $bill_table->put($x,7, $paybill); $x++; }#end foreach loop
Update> I get the following error: Use of uninitialized value in numeric eq (==) at BPP/BILL.pm line 148. Which is this line: if ($checkboxvalue[$t] == 1

Replies are listed 'Best First'.
Re: Array of TK::Checkbuttons not acting appropriately
by GrandFather (Saint) on Oct 02, 2006 at 02:16 UTC

    We need to see less code. Focus down on the two lines that are causing your trouble and just enough other lines so that we can reproduce it. Your sample code has far too many unknown entities. Try adding use strict; use warnings; and if it doesn't compile clean (appart from your error) then clean it up.

    Are any of the ->put lines relevant to the problem?

    I'd guess you are after something like the following (but I can't tell from your code):

    use strict; use warnings; use Tk; my @unpaidbills = (['Fred', 1.27], ['Joe', 3.46], ['Francis', 2.22], [ +'Joanne', 5.23]); my @checkboxes; my $main = new MainWindow; foreach my $bill (@unpaidbills) { my $state = 0; # Note we get a new $state each time through my $button = $main->Checkbutton ( -text => "$bill->[0]: $bill->[1]", -variable => \$state ); $button->pack (); $checkboxes[@checkboxes] = [$button, $bill, \$state]; } $main->Button(-text=>'Submit', -command=> [\&doSubmit, \@checkboxes])- +>pack (); MainLoop (); sub doSubmit { my ($checkboxes) = @_; for my $entry (@$checkboxes) { my ($button, $bill, $state) = @$entry; if ($$state) { print "$bill->[0] paid \$$bill->[1]\n"; } else { print "\$$bill->[1] not paid for $bill->[0]\n"; } } }

    DWIM is Perl's answer to Gödel

      This is the line that is erroring

          if ($checkboxvalue[$t] == 1)

      This is the error

      Use of uninitialized value in numeric eq (==) at BPP/BILL.pm line 148.

      I declare @checkboxvalue = () as such.

      Should I do this also $checkboxvalue$t = 0; ?
      I dont' understand why it is "uninitialized".

      Update:
      It seems that when I click the checkbox the onValue is not being set. So below is my declaration of the Checkbutton

      $checkbox[$t] = $bill_table->Checkbutton(-variable=>\$checkboxvalu +e[$t]);

      Perhaps -variable is not what I should use. I'm going to read more on the Checkbutton options

        I suggest you converge your problem code toward the sample I gave. If your problem remains at the end of that process, post the code and we will help further.

        Your immediate problem is likely to be that you are indexing an element that wasn't present in the array, so it is being created for you and set to undef. It is not clear from your code where $t may be set to anything other than 0, but it seems likely in your "real" code that it is.

        Again I suggest that you reproduce the problem in a small sample application (see my sample as a guide) that we can run and check.


        DWIM is Perl's answer to Gödel
Re: Array of TK::Checkbuttons not acting appropriately
by rcseege (Pilgrim) on Oct 02, 2006 at 02:01 UTC

    Updated: Added code to example to include -command option for Checkbutton.

    Updated Again: Created a second example based on my first, to try and more closely duplicate the scenario - I still don't see the same problem.

    Why do you insist on making it difficult for people to help you? A small working example might have even shown you the solution before you posted the question. My guess is that you are setting the same variable for each Checkbutton because I don't see you incrementing t anywhere.

    This example worked for me:

    use strict; use Tk; my @cbValues; my $mw = MainWindow->new; $mw->Button( -text => "Print Selected", -command => \&printSelected )->pack; my $rows = $mw->Frame->pack; ## $rows will serve as a gridded container for each ## of the checkbutton rows. This should be roughly ## similar to using Tk::Table, but less hassle ## for a quick & dirty example. for my $row (0 .. 9) { $rows->Label(-text => $row)->grid( $rows->Checkbutton( -command => [\&select, $row], -variable => \$cbValues[$row])); } MainLoop; sub select { my $i = shift; if ($cbValues[$i]) { print "Selected $i\n"; } else { print "Deselected: $i\n"; } } sub printSelected { my $row = 0; print "\nSelected:\n"; foreach my $val (@cbValues) { print "$row selected\n" if $val; $row++; } }

    Another example with a submit button for each row:

    use Tk; use strict; my @cbValues; my $mw = MainWindow->new; $mw->Button( -text => "Print Selected", -command => \&printSelected )->pack; my $rows = $mw->Frame->pack; ## $rows will serve as a gridded container for each ## of the checkbutton rows. This should be roughly ## similar to using Tk::Table, but less hassle ## for a quick & dirty example. for my $row (0 .. 9) { $rows->Checkbutton( -text => $row, -variable => \$cbValues[$row] )->grid( $rows->Button( -text => "Submit", -command => sub { if ($cbValues[$row] == 1) { print "$row selected\n" } else { print "$row unselected\n"; } })); } MainLoop; sub printSelected { my $row = 0; print "\nSelected:\n"; foreach my $val (@cbValues) { print "$row selected\n" if $val; $row++; } }
    Rob
      Oh sorry.
      I do increment $t in my program. Didn't paste that line sorry.

      Why do you insist on making it difficult for people to help you? A small working example might have even shown you the solution before you posted the question.
      Why are you so mean?? I have a small program and that is not the solution - (the $t increment) I am doing that in my program.

      If you have to be condescending and mean just don't respond because it doesn't help me solve my problem.
      Thanks!

        rcseege wasn't being mean. He was trying to be helpful. He actually said much the same thing that I did and for the same reason - you have posted a chunk of code that we can't run and can't even analyse in any sensible fashion because it contains a pile of irrelevant code and some code that may be important, but which is clearly using objects that we know nothing about.

        The best we can do is guess at what your problem is, and Rob did correctly identify at least one problem with the code you posted.

        It is time to be humble, appologise to Rob for complaining about his help and think about how you might present your problem in a fashion such that we can actually help you with it.

        It may help you to read I know what I mean. Why don't you? when reformulating your question.


        DWIM is Perl's answer to Gödel

        I do apologize for coming across as mean or condescending -- that really was not my intent. I admit that I was a bit incredulous and slightly frustrated with the messy snippet you provided which wouldn't run and was littered with references to things defined elsewhere. You didn't even take the few moments required to clean things up a bit so that it would be more readable... I may be overstating things, but I found it borderline offensive, and also not very helpful in getting a resolution to your problem.

        Please try modifying one of the other examples provided so that they show the same error condition.

        Regards,

        Rob
Re: Array of TK::Checkbuttons not acting appropriately
by Koosemose (Pilgrim) on Oct 02, 2006 at 02:35 UTC

    Yeah, as rcseege demonstrated in their example, there really isn't a need for a variable to hold the checkbox widgets, so all you really need is

    $bill_table->Checkbutton(-variable=>\$checkboxvalue[$t])->pack;

    I'm assuming that somewhere in your code you increment $t, since this appears to be just a snippet, or hopefully just a badly put together example. Ideally you'd want to create and pack your checkbuttons seperate from the rest of the code. Something along the lines of the following:

    my @checkbox = (qw/fred george jimbo frank/); foreach $c (0..@#checkbox) { $bill_table->Checkbutton(-variable=>\$checkboxvalue[$c],-text=>@chec +kbox[$c])->pack; }

    Update: What you really need to do, to help us help you is trim it down to just what's causing the error, but with enough code that we can actually run the script, it's alot easier to debug something when we have a working program, with the smallest amount of code that still generates the same error you get. and as rcseege said, you may just find out what's wrong yourself when trying to trim it down to a functional test case.

    Just Another Perl Alchemist
Re: Array of TK::Checkbuttons not acting appropriately
by rcseege (Pilgrim) on Oct 02, 2006 at 09:21 UTC

    I still don't have an answer as to what is going wrong, but I did take a few moments and tried to move my second example even closer to what I'm guessing you were going for. Admittedly, I left out a column, but didn't have a good idea what you were doing there, so I ignored it.

    Since this third example is a little closer to what I think you were going for, maybe it will help. After thinking more about the snippet you provided, I do have a few questions/recommendations:

    1. Why is there a Checkbutton and a Submit Button on each row? I would have thought that you could get by with one or the other. I'm guessing that the Submit button will cause another window with editable text fields to appear, populated with the data for a row. It seems like an unnecessary extra step to have to select the Checkbutton, too.

    2. Avoid Tk::Table - Not because it's a bad widget -- it's Ok, and it does work, but it's an efficient way to display tabular data, and there are other arguably better options available such as HList or TableMatrix. For large data sets, Tk::Table will consume far more memory than say: HList or TableMatrix.

    3. You don't have to maintain a reference to each Checkbutton. Especially since you are using Tk::Table. You can access any widget stored inside it so long as you know it's row and column -- the same can be done with the grid geometry manager

Re: Array of TK::Checkbuttons not acting appropriately
by mikasue (Friar) on Oct 02, 2006 at 12:33 UTC

    Thanks for your help. I have been trying to figure this out all weekend and got a little frustrated.

    Forgive me everyone.

    Here is a little snippet that everyone can run to see my problem. The problem again is when I click 1 checkbutton they all get selected.

    use strict; use warnings; use Tk; use Tk::Table; our $MW = MainWindow->new(%{$BPP::BPPDEFAULTS::MYDEFAULTS{MAINWINDOW}} +); $MW->geometry('800x700+0+0'); my $tableframe = $MW->Frame(-background=>'white' )->pack(-side=>'top', -fill=>'both', -pady=>20); my $bill_table = $tableframe->Table(-rows=>2, -columns=>3, -background=>'pink', -scrollbars=>'e' )->pack(-fill=>'both', -side=>'top', -anchor=>'s'); my @foo = qw/ Apple Oranges Pears/; my $x = 1; my $checkbox; my $checkboxvalue = 0; foreach my $f (@foo) { $checkbox = $bill_table->Checkbutton(-variable=>\$checkboxvalue); $bill_table->put($x,0, $checkbox); $bill_table->put($x,1, $f); $bill_table->Button(-text=>'Submit', -command=>sub{print $f} )->pack; $x++; }#end foreach loop MainLoop;

    So to distinguish them I tried putting the -variable value in an array. This fixes the selection issue but then that -variable value is not being set when I click on the checkbutton. I get this error: Use of uninitialized value in numeric eq (==)

    use strict; use warnings; use Tk; use Tk::Table; our $MW = MainWindow->new(%{$BPP::BPPDEFAULTS::MYDEFAULTS{MAINWINDOW}} +); $MW->geometry('800x700+0+0'); my $tableframe = $MW->Frame(-background=>'white' )->pack(-side=>'top', -fill=>'both', -pady=>20); my $bill_table = $tableframe->Table(-rows=>2, -columns=>3, -background=>'pink', -scrollbars=>'e' )->pack(-fill=>'both', -side=>'top', -anchor=>'s'); my @foo = qw/ Apple Oranges Pears/; my $x = 1; my $t=0; my $checkbox; my @checkboxvalue; foreach my $f (@foo) { $checkbox = $bill_table->Checkbutton(-variable=>\$checkboxvalue[$t]); $bill_table->put($x,0, $checkbox); $bill_table->put($x,1, $f); $bill_table->Button(-text=>'Submit', -command=>sub{if ($checkboxvalue[$t] ==1){prin +t $f}} )->pack; $x++; $t++; }#end foreach loop MainLoop;

    I hope this makes my problem clearer.
    ================================================

    I need a Checkbutton and a Submit button on each line becuase there will be distinct information I need to change on each line. When the Checkbutton is selected, the information in that line is editable and the Submit button submits those changes for that line only.

    I also need a reference to the checkbutton in order to PUT it in the table.

    $checkbox = $bill_table->Checkbutton(-variable=>\$checkboxvalue[$t]); $bill_table->put($x,0, $checkbox);

    Thanks again for all ya'll help

      The problem is with the closure (the anonymous sub{...}</> that -command is) and the scope of $t.  Put a <c>warn $t in the sub{} to see what it's doing -- you'll see that it's always 3 which is the value of t after the foreach my $f (@foo) ... Here are two different approaches to solving it:

      Here, you can use a temp value to hold the current value of $t. Since $i is scoped inside the for loop, it is different for each closure that is made.
      my $i=$t; $bill_table->Button(-text=>'Submit', -command=>sub{if ($checkboxvalue[$i] ==1){prin +t $f}}, )->pack;
      Alternatively, use the form of Tk::callback that lets you provide arguments to a sub. Here our anonymous sub takes two args -- a reference to a scalar which is the checkbox value, and a scalar which is the text of the checkbox.
      $bill_table->Button(-text=>'Submit', -command=>[ sub{ my $valref = shift; my $valname=shift; if ($$valref ==1){print $valname} }, \$checkboxvalue[$t], $f, ], )->pack;
      Now, there's the issue of your Use of uninitialized value in numeric eq (==) .. That is because the checkbox values are either 1 or undef, so when you check <thecheckboxvalue>==1 it'll do either 1==1 (ok) or undef==1 (warning).
      To solve, simply do one of these (probably the first? not sure that being exactly 1 is important, as long as it's true:
      if( $foo ){ print $f } if( defined $foo ){ print $f } if( $foo && $foo==1){ print $f } if( defined $foo && $foo==1){ print $f }
        That is because the checkbox values are either 1 or undef

        I'm a little puzzled. Checkbutton values are supposed to be 1 or 0, defaulting to 0, though I can't argue with what I'm seeing. Try selecting, then deselecting a Checkbutton using mikasue's last example. When you press the Submit button for that row now, you shouldn't see the "Use of unitialized..." message, because now the value is 0 instead of undef. I'm going to have to take another look at why my second and third examples didn't behave this way.

        Having said that, I agree that your first condition:  if ($foo) { ... } is best for this.

        Rob
        THANK YOU davidrw!!!!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://575826]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-04-25 16:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found