In quite a few locations you could have abstracted a bit more. F.ex:
my $cmds = $tl->Frame; $cmds->pack; if (defined $idx) { # Existing activity - OK Apply Delete Cancel $cmds->Button(-text => 'OK', -command => sub {&edit_entry($idx,$le +gentry);$tl->destroy;}) ->pack(-side => 'left'); $cmds->Button(-text => 'Apply', -command => [\&edit_entry, $idx, $ +legentry]) ->pack(-side => 'left'); $cmds->Button(-text => 'Delete', -command => sub {&delete_entry($i +dx);$tl->destroy;}) ->pack(-side => 'left'); } else { # New activity - OK Apply Cancel $cmds->Button(-text => 'OK', -command => sub {&add_entry($legentry +);$tl->destroy;}) ->pack(-side => 'left'); $cmds->Button(-text => 'Apply', -command => [\&add_entry, $legentr +y]) ->pack(-side => 'left'); } $cmds->Button(-text => 'Cancel', -command => [$tl => 'destroy'])->pack +(-side => 'left');
You can write that as:
my @button = defined $idx ? ( OK => sub { &edit_entry($idx,$legentry); $tl->destroy; }, Apply => [\&edit_entry, $idx, $legentry], Delete => sub { &delete_entry($idx); $tl->destroy; }, Cancel => [$tl => 'destroy'], ) : ( OK => sub { &add_entry($legentry); $tl->destroy; }, Apply => [\&add_entry, $legentry], Cancel => [$tl => 'destroy'], ); for($tl->Frame) { $_->pack; while(my ($text, $command) = splice @button, 0, 2) { $_->Button(-text => $text, -command => $command) ->pack(-side => 'left'); } }

Note how the layout now directly conveys the information you previously had to sum up in comments.

If you don't like the scoping to main:: (I don't either), and you have a relatively involved data structure, that usually means you should abstract out your backend logic into a class. Use Class::Accessor to save the hassle of writing a lot of accessors and mutators and life is good. See also Damian Conway's ten rules for when to use OO.

F.ex given a class Activity, and with a slightly different INI format, you could have wittled down this:

print SAVE <<END; for (0..$#activity) { my ($legend,$time,$start,$end,$elapsed) = @{%{$activity[$_]}}{qw(legend timstr start end elapsed)}; # Add up times of current activity my $tsecs = 0; for my $i (0..$#$end) { $tsecs += tv_interval($start->[$i],$end->[$i]); } $tsecs += $elapsed if $elapsed; $tsecs += tv_interval($start->[-1],[gettimeofday]) if defined($cur +rent) && ($_ == $current); print SAVE <<END2; [Button $legend] time=$time elapsed=$tsecs END2 }
to this:
for (@activity) { print SAVE "[Button]\n"; my $item; print SAVE "$item=" . $_->$item() for qw(legend time elapsed); }

with calculation for time elapsed being hidden away at the particular spot, since it's not where it logically belongs anyway.

In general, try to abstract a bit more - capture regularities in code, irregularities in data.

Makeshifts last the longest.


In reply to Re: Tk programming style by Aristotle
in thread Tk programming style by rinceWind

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.