Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re: Some beginning Tk help

by Util (Priest)
on Jun 22, 2002 at 21:14 UTC ( [id://176535]=note: print w/replies, xml ) Need Help??


in reply to Some beginning Tk help

Two different solutions:
  1. pack/grid hybrid: Use pack to position Pane and Label, and give pack the options to dynamically resize Pane. Use grid to position buttons within Pane.
    Oops, kvale beat me to this one.
  2. pack only: Put each set of 4 radiobuttons in a Frame, and pack the frames into Pane.
Other general recommendations:
  • For your button variables, in each row, use the same variable for each of the 4 buttons, otherwise pressing one won't clear the other three!
  • For your button variables, use an array instead of soft-referenced global variables.
  • Use warnings (or -w) and strict.
  • Add use Tk::Pane to prevent the "Assuming 'require Tk::Pane;'" warning.
  • If you are using grid, then make your first row Labels, to avoid having to label each button.
  • Use Data::Dumper during testing to see the values of your input controls.
The code below demonstrates all the recommendations, and both solutions.
#!/usr/bin/perl -w use strict; use Tk; use Tk::Pane; # Set to 0 or 1 before running. my $grid_method = 1; my $mw = MainWindow->new( -title => "SACL Survey" ); my $pane = $mw->Scrolled(qw/Pane -scrollbars osow/)->pack( -expand => 'yes', -fill => 'both', ); $mw->Label( -text => "... <insert directions here> ..." )->pack(); my @button_values; if ($grid_method) { foreach my $j (1..4) { $pane->Label( -text => $j, )->grid( -column => $j, -row => 1, ); } foreach my $i (1..30) { foreach my $j (1..4) { $pane->Radiobutton( -value => $j, -variable => \$button_values[$i-1], )->grid( -column => $j, -row => $i+1, ); } } } else { foreach my $i (1..30) { my $frame = $pane->Frame->pack(); foreach my $j (1..4) { $frame->Radiobutton( -text => $j, -value => $j, -variable => \$button_values[$i-1], )->pack( -side => 'left', ); } } } MainLoop; use Data::Dumper; print Dumper \@button_values;

Replies are listed 'Best First'.
A node misplaced. . .
by dimmesdale (Friar) on Jun 22, 2002 at 23:41 UTC
    Well, I couldn't figure out how to update the node after a few minutes, so I'll reply (It's been a while since I've been here).

    Thanks for all the solutions (especially the general recommendations--it's been a while since I've been using Perl, and just getting back to it I find that I've forgot some things).

    I, however, have another question

    It's just to get me pointed in the right direction. I was thinking it might be desirable that one group of radio buttons were displayed at one time (with buttons saying first, previous, next). Would all that would be required to do this be to undraw the current screen (via the forget method?) and then re-draw with the desired buttons (and, of course, handle in the command subs which buttons need to be drawn)? I want to make sure that I'm not missing any subtelties somewhere.

    Update: I changed the code around a little bit (minor things), and came across one final question. In order to make a 'finalized' product, so to speak, it would be nice if I knew how to make a Tk window that would open to a specified size. I looked through Mastering Perl/Tk, and got the notion that the geometry method might have something to do with it, but the book never explicitly said anything about how to (that I saw). What I'm thinking, for this example, is to have the code run, and come up simply as a rectangle that displays all the information (buttons) in one window. What would be the general method for this?

    (A side thought: since there's usually a preview button around when one is submitting a node for the first time, would such a button be desirable when editing a node?)

    Update 2
    Well, its not necessary for an answer I guess, but here's the code I forgot to put up before (hmm. . . about that preview button. . .)

    #!/usr/bin/perl -w use strict; use Tk; use Tk::Pane; ## In case this seems mysterious, the example is eventually ## going to administer a survey in which the participant ## responds with a 1-4 about certain adjectives my @words = ("word") x 30; my $mw = MainWindow->new( -title => "SACL Survey" ); my $pane = $mw->Scrolled(qw/Pane -scrollbars osow/)->pack( -expand => 'yes', -fill => 'both', ); my $frame = $pane->Frame->pack(); $mw->Label( -text => "... <insert directions here> ..." )->pack(); my @button_values; my @frame_widgets; my $unanswered = 30; sub button_set { my $i = int(shift); my $prev = $i - 1; my $next = $i + 1; my $first = 1; my $last = 30; $prev = $first if $prev < $first; $_->destroy foreach reverse @frame_widgets; @frame_widgets = (); push @frame_widgets, $frame->Label( -text => "#$i. $words[$i-1]", )->pack(); push @frame_widgets, $frame->Button( -text => "First", -command => sub { set_unasnwered(); button_set($first) }, )->pack( -side=>'left', ); push @frame_widgets, $frame->Button( -text => "Back to $prev", -command => sub { set_unasnwered(); button_set($prev) }, )->pack( -side=>'left', ); foreach my $j (1..4) { push @frame_widgets, $frame->Radiobutton( -text => $j, -value => $j, -variable => \$button_values[$i-1], )->pack( -side => 'left', ); } my $state1 = ("normal","disabled")[$next > $last]; push @frame_widgets, $frame->Button( -text => "Forward to $next", -command => sub { set_unasnwered(); button_set($next) }, -state => $state1, )->pack( -side => 'left', ); my $state2 = ("disabled","normal")[$unanswered < 1]; push @frame_widgets, $frame->Button( -text => "Finished", -command => sub { $mw->destroy; calc() }, -state => $state2, )->pack( -side => 'left', ); } sub set_unasnwered { my $i = 29; foreach my $j (@button_values) { $i-- if $j } $unanswered = $i; } sub calc { # Make sure all questions are answered due to few, but unlikely, #ways of getting past the preliminary check my $i = 30; foreach my $j (@button_values) { $i-- if $j } if ($i > 0) { print "Survey not completed. Exiting. . ."; exit } # Calculate score and save to file (Survey is indeed completed) } button_set(1); MainLoop; use Data::Dumper; print Dumper \@button_values;

      I couldn't figure out how to update the node
      See How do I change/delete my post?

      Would all that would be required to do this be to undraw the current screen (via the forget method?) and then re-draw with the desired buttons

      1. I think (but have not verified) that just using gridForget or packForget would cause a memory leak, for they only remove the widget from screen management; they don't actually get rid of the widget. Calling destroy does both.
      2. You only have to destroy and recreate the affected widgets, if they are all in one Frame or other pack-able container; no need to do the whole screen.

      Other than that, you are correct. Here is an implimentation:
      #!/usr/bin/perl -w use strict; use Tk; use Tk::Pane; my $mw = MainWindow->new( -title => "SACL Survey" ); my $pane = $mw->Scrolled(qw/Pane -scrollbars osow/)->pack( -expand => 'yes', -fill => 'both', ); my $frame = $pane->Frame->pack(); $mw->Label( -text => "... <insert directions here> ..." )->pack(); my @button_values; my @frame_widgets; sub button_set { my $i = int(shift); my $prev = $i - 1; my $next = $i + 1; my $first = 1; my $last = 30; $prev = $first if $prev < $first; $next = $last if $next > $last; $_->destroy foreach reverse @frame_widgets; @frame_widgets = (); push @frame_widgets, $frame->Label( -text => "Survey Question #$i", )->pack(); push @frame_widgets, $frame->Button( -text => "First", -command => sub { button_set($first) }, )->pack( -side=>'left', ); push @frame_widgets, $frame->Button( -text => "Back to $prev", -command => sub { button_set($prev) }, )->pack( -side=>'left', ); foreach my $j (1..4) { push @frame_widgets, $frame->Radiobutton( -text => $j, -value => $j, -variable => \$button_values[$i-1], )->pack( -side => 'left', ); } push @frame_widgets, $frame->Button( -text => "Forward to $next", -command => sub { button_set($next) }, )->pack( -side => 'left', ); push @frame_widgets, $frame->Button( -text => "Last", -command => sub { button_set($last) }, )->pack( -side => 'left', ); } button_set(1); MainLoop; use Data::Dumper; print Dumper \@button_values;

      A side thought: since there's usually a preview button around when one is submitting a node for the first time, would such a button be desirable when editing a node?
      I have wished that it were so, but I have searched for discussions about this, and found much disagreement. As a workaround, you can use your scratchpad to preview anything you care to write.

      Update: ... and came across one final question.
      In future posts, please consider making this kind of update into a separate reply instead. It will be easier for other monks to follow the conversation. As it is, no one can tell for sure that my second reply was to the pre-update version of your reply, and my third reply was to the post-update version of your reply. It is clear to you and I today, but it will be less clear to future monks searching for enlightenment.

      ...have the code run, and come up simply as a rectangle that displays all the information (buttons) in one window.
      The window manager should do this automatically. After a good night's sleep, I see that I missed something in my last example. Now that we are not displaying all 30 button sets at once, we no longer need the scrolling, and so $pane can be removed, allowing $frame to become a child of $mw. After this change, the application starts up with the correct size. In diff notation:

      -my $pane = $mw->Scrolled(qw/Pane -scrollbars osow/)->pack( - -expand => 'yes', - -fill => 'both', -); -my $frame = $pane->Frame->pack(); +my $frame = $mw->Frame->pack();
      Does this do what you wanted?
        Perfect.

        (I skipped right over the 'Comment on ...' link, b/c I was looking for a 'Reply to' link like on all the replies; I assume that's what you were talking about {Util})

        It works for my purposes here, but is there a way to make it any size you want? It seems somewhat limiting if there isn't (but maybe it's just me, and the need doesn't come up often enough).

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (5)
As of 2024-03-28 08:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found