http://www.perlmonks.org?node_id=737749

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

I am building my very first GUI. I have cobbled the bones together but it is an example of poor code, and very redundant. Can I get some pointers on introducing hashes and optimizing this for many "programs"?
use warnings; use strict; use Tk; use Tk::NoteBook; require Tk::Pane; use Tk::LabEntry; my $mw = MainWindow->new; $mw->geometry( "600x500" ); $mw->title("Survival Kit"); ##mainwindow, scroll, frames## my $spane=$mw->Scrolled('Pane')->pack(-expand=>1,-fill=>'both'); my $frame1=$spane->Frame()->pack(-side=>'left',-expand=>1,-fill=>'both +',-padx=>15); my $frame2=$spane->Frame(-padx=>15)->pack(-side=>'right',-expand=>1,-f +ill=>'both'); ##Checkbuttons## my ($pgr1_on,$pgr2_on); my $pgr1_but=$frame1->Checkbutton(-text => "program1 ", -variable => \ +$pgr1_on )->pack; my $pgr2_but=$frame1->Checkbutton(-text => "program2 ", -variable => \ +$pgr2_on )->pack; ##OPEN button## my $open=$mw->Button(-text => "Open\n Tool (s)", -command => \&but)->p +ack( -side=>'bottom', -pady=>20); MainLoop; ####################################### sub but { ## kill top window $spane->destroy($open); ## create notebook #my $sub_spane=$mw->Scrolled('Pane')->pack(-expand=>1,-fill=>'both'); my $book = $mw->NoteBook()->pack(-expand=>1,-fill=>'both'); #my $sub_frame1=$book->Frame()->pack(-side=>'left',-expand=>1,-fill=>' +both'); #my $sub_frame2=$book->Frame()->pack(-side=>'right',-expand=>1,-fill=> +'both'); #####program1####### if ($pgr1_on){ ##create tab,scroll pane,frames my $pgr1_tab=$book->add("Sheet 1", -label => "program1")->pack(-expa +nd=>1,-fill=>'both'); my $sub_spane=$pgr1_tab->Scrolled('Pane')->pack(-expand=>1,-fill=>'b +oth'); my $sub_frame1=$sub_spane->Frame()->pack(-side=>'left',-expand=>1,-f +ill=>'both',-padx=>15); my $sub_frame2=$sub_spane->Frame(-padx=>15)->pack(-side=>'right',-ex +pand=>1,-fill=>'both'); ##now fill frames my @pgr1_default = qw( 1 2 3 4 5 6 7 8 9 10 ); my $pgr1_cnt=0; our $pgr1_parms; foreach my $val qw( PARM1 PARM2 PARM3 PARM4 PARM5 PARM6 PARM7 PARM8 + PARM9 PARM10){ if ($pgr1_cnt < 5){ $sub_frame1->LabEntry(-label => "$val=", -textvariable => "$pgr1_ +default[$pgr1_cnt]" )->pack; } else{ $sub_frame2->LabEntry(-label => "$val=", -textvariable => "$pgr1_ +default[$pgr1_cnt]" )->pack; } $pgr1_parms .= "$val=$pgr1_default[$pgr1_cnt]\n"; $pgr1_cnt++; } } ################### #####program2####### if ($pgr2_on){ ##create tab,scroll pane,frames my $pgr2_tab=$book->add("Sheet 2", -label => "program2")->pack(-expa +nd=>1,-fill=>'both'); my $sub_spane=$pgr2_tab->Scrolled('Pane')->pack(-expand=>1,-fill=>'b +oth'); ##now fill frames my @pgr2_default = ("./","list","./","Y","N"); my $pgr2_cnt=0; our $pgr2_parms; foreach my $val qw( IN_DIR IN_LIST OUT_DIR PARM1 PARM2 ){ $sub_spane->LabEntry(-label => "$val=", -textvariable => "$pgr2_d +efault[$pgr2_cnt]" )->pack; $pgr2_parms .= "$val=$pgr2_default[$pgr2_cnt]\n"; $pgr2_cnt++; } } ############################## ########Exit button########### ##disappears after reset? Implement save? my $leave=$mw->Button(-text => "Save & Exit ",-command => \&save_parms +)->pack; ############################## #######Reset button############# ##needs better implementation? my $return=$mw->Button(-text => "Reset ", -command => \&rtn)->pack( -s +ide=>'bottom', -pady=>20); sub rtn{ system 'perl easydoesit.35basictestBEST2 &'; exit; } ############################# our ($pgr1_parms,$pgr2_parms); sub save_parms { open (SP1,">>pgr1_parms.txt"); print SP1 $pgr1_parms; close SP1; open (SP2,">>pgr2_parms.txt"); print SP2 $pgr2_parms; close SP2; exit; } }
Thanks.

Replies are listed 'Best First'.
Re: clunky Tk GUI
by vkon (Curate) on Jan 21, 2009 at 12:23 UTC
    because of this hairy Tk GUI code, I switched to a different Tk programming technique in all my programs.

    The idea is to use pure-Tcl/Tk for constructing GUI, but then use perl/Tk style for operating widgets.

    use strict; use Tcl::Tk; my $mw = Tcl::Tk::tkinit; my $int = $mw->interp; $int->Eval(<<'EOS'); # here goes pure-Tk GUI creation package require BWidget package require tooltip menu .menu -tearoff 0 menu .menu.file -tearoff 0 menu .menu.help -tearoff 0 .menu.help add command -label {brief explanation... (F1)} -command exp +lainBox .menu.help add command -label {About...} -command aboutBox .menu.file add separator .menu.file add command -label Exit -command {destroy .} .menu add cascade -menu .menu.file -label File .menu add cascade -menu .menu.help -label Help . config -menu .menu wm title . {Here goes the title} pack [text .t -wrap none -font "Courier 8"] -expand 1 -fill both pack [button .b -text "test button" -command "puts this"] -fill x tooltip::tooltip .b "helper tooltip" # and now 2 helper dialog boxes: proc aboutBox {} { Dialog .about -modal local -separator 1 -title {about...} pack [message [.about getframe].m1 -text {author - me}] .about add -name Ok -text Ok .about setfocus 0 .about draw destroy .about } proc explainBox {} { Dialog .explain -modal local -separator 1 -title {brief explanatio +n} set vt [.explain getframe] pack [message $vt.m1 -text {This program does foo bar fluffy, bla- +bla-bla} -width 450] .explain add -name Ok -text Ok .explain setfocus 0 .explain draw destroy .explain unset vt } bind . <Key-F1> explainBox bind . <Control-Key-F1> aboutBox EOS # bind Tcl/Tk widget to the perl/Tk my $t = $int->widget(".t",'Text'); # do anything with perl/Tk syntax $t->insert('end','some-text'); $t->see('end'); $int->MainLoop;

    Same GUI creation perl/Tk will be thrice as much code.

    This technique requires some additional efforts to start with, but I get very much benefits, so I never look back

Re: clunky Tk GUI
by zentara (Archbishop) on Jan 21, 2009 at 14:00 UTC
    See Re: Tk Notebook tab columns for an example of using hashes and notebooks to maintain order. Also remember the power of the -createcmd and -raisecmd options of the NoteBook widget. They allow you to adjust pages (fill them with data) as you create or raise the tabs.

    I'm not really a human, but I play one on earth Remember How Lucky You Are
      Thank you. I adapted this from your previous reply but, as a PERL dabbler, I am a bit perplexed by your hash structures. Can you add more explanation to your earlier code?
        Well it's all about hashes, and it's a big topic. I will reccomend you to the tutorials at Data Type: Hash. Now, I will try to give a brief explanation of how it all works.

        Instead of storing individual widgets in separate scalars, you can store those scalars in a orderly hash structure, which will allow you to access them by a key. So for instance, say you had 2 pages, and 3 widgets on each page. You could be "clunky" and call them $page1_widget1, $page1_widget2, $page1_widget3, and $page2_widget1, $page2_widget2, $page2_widget3.

        You can see how clunky that is. An alternative, would be to store them all in a hash, like

        my %hash; # NOT my $hash, unless you want to set it up reference sty +le # then create in loops $hash{$page}{$widget} #like foreach my $page(1..2){ #add the page $hash{$page}{'page'} = $nb->add(......) #fill each page with widgets foreach my $widg( 1..3){ $hash{$page}{$widj} = $hash{$page}{'page'}->Button(.....opt +ions.) } }
        Now, all you need to do to access any widget, is the $page and $widget number. For instance, the 2ond widget on page2, would be $hash{2}{2}. ( or $hash{$page}{$widj} )

        This is a very simple example of course, and real world apps each need the best hash setup. It sort of is an art that is learned by spending a few afternoons setting up hashes and experimenting. There are 2 great benefits to storing widgets in a hash.

        1. It makes accessing and looping thru them easy. You can loop thru all the widgets on page2 for instance.

        2. And this comes later.... if you want to put your script into a package or module, the hash is already setup to be blessed. Instead of $hash{$page}{$widj} you would have $self->{$page}->{$widj}.

        A whole book could be written on this, so I'm stopping now. Just play around with simple apps, and store things in hashes...it won't take long for you to figure it out.


        I'm not really a human, but I play one on earth Remember How Lucky You Are