Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Simple Calculator using Tk

by eoin (Monk)
on Feb 19, 2004 at 17:57 UTC ( #330287=sourcecode: print w/replies, xml ) Need Help??
Category: GUI Programming
Author/Contact Info eoin
eoinmurphy00@hotmail.com
http://eoin.perlmonk.org
Description: Just a simple calculator made using Tk; It was a refresher in Tk, god knows I needed it. Its my first posted code so don't be too harsh.
use strict;
use warnings;
use diagnostics;

use Tk 800;
use Tk::Entry;
use Tk::Button;
use Tk::DialogBox;

my $calc    = '0.00';
my $r       = 0;
my $w       = '0';
my $h       = 1;
my $buffer  = '';
my $dbuffer = '';
my %button;
my @rows;


my $mw = new MainWindow(-title => 'Calc');
$mw->geometry("300x300");


my $menubar = $mw->Menu;
$mw->configure(-menu => menuconf());

my $topframe = $mw->Frame(-height => '60', -width => '300')->pack(-sid
+e => 'top', -expand => '0', -fill => 'x');
my $btmframe = $mw->Frame(-height => '225', -width => '300',)->pack(-s
+ide => 'left', -expand => '1', -fill => 'both');
push @rows, $btmframe->Frame()->pack( -expand => 1, -fill => 'both', -
+side => 'top') for (0..3);

my $display   =  $topframe->Entry(-justify      => 'right',
                                  -state        => 'disabled', 
                                  -textvariable => \$calc)
                           ->pack(-expand       => '1',
                                  -fill         => 'x',
                                  -pady         => 30,
                                  -padx         => 20,
                                  -side         => 'right');

$mw->bind("<KeyRelease>" , sub { &keypress } );


for my $i (
qw/
   7 8 9 * n*
   4 5 6 - \/
   1 2 3 + =
   0 . C     / )
{

if($i eq '+' || $i eq '=')
{
$h = 3;
}


$button{$i} = $rows[$r]->Button(-text    => "$i", 
                                -width   => '3', 
                                -height  => "$h", 
                                -command => sub { &btnpress($i) })
                         ->pack(-expand  => 1,
                                -fill    => 'both',
                                -padx    => 2, 
                                -pady    => 2,
                                -side    => 'left',
                                -ipadx   => 5, 
                                -ipady   => 5);

$w++;
$h = 1;

if($w > 4){$w = 0; $r++;}
}



MainLoop;


sub btnpress{
my $btn = shift;

if($btn eq 'n*' && $buffer ne '')
{
   $btn = '**';
   calc($btn);
}

elsif($btn eq 'C')
{
   $calc   = '0.00';
   $buffer = '';
   $dbuffer= '';
}

elsif($btn eq '=')
{
   $buffer = eval($buffer);
   $calc = sprintf "%0.2f", $buffer;
}

else
{  
   calc($btn);
}
}

sub calc{

 my $btn = shift;
 $buffer = $buffer . $btn;

 if( $btn =~ /(\d)|\./){ $dbuffer = $dbuffer . $btn }

 unless( $btn =~ /(\d)|\./){ $calc = ''; $dbuffer = ''; }
 
 if( $btn =~ /(\d)|\./){ $calc = sprintf "%0.2f", $dbuffer; }
}


sub keypress{

 if($_[0] ne 'q'){
 my $widget = shift;
 my $e = $widget->XEvent;    # get event object
 my $btn = $e->K;
 $btn=~s/period/\./ig;

 if( $btn =~/c/ig ){ $btn = uc $btn; $button{$btn}->invoke; }
 if( $btn =~/q/ig ){ exit 0; }    
 if( $btn =~/(\d)|\./){ &btnpress($btn); }
}
else
{
exit 0;
}
}

sub menuconf{

 my $file_menu = $menubar->cascade(-label => "~File");
 my $func_menu = $menubar->cascade(-label => "~Function");
 my $help_menu = $menubar->cascade(-label => "~Help");

 $file_menu->command(-label => "~Clear     C",     -command => sub { \
+&btnpress('C' );  });
 $file_menu->command(-label => "~Exit      Q",     -command => sub { \
+&keypress('q' );  });
 $func_menu->command(-label => "~Add       +" ,    -command => sub { \
+&btnpress('+' );  });
 $func_menu->command(-label => "~Minus     -" ,    -command => sub { \
+&btnpress('-' );  });
 $func_menu->command(-label => "~Multiply  x" ,    -command => sub { \
+&btnpress('x' );  });
 $func_menu->command(-label => "~Divide    /" ,    -command => sub { \
+&btnpress('/' );  });
 $func_menu->command(-label => "~Power of  n*",    -command => sub { \
+&btnpress('n*');  });
 $func_menu->command(-label => "~Equals    =" ,    -command => sub { \
+&btnpress('=' );  });
 $help_menu->command(-label => "~About"       ,    -command => sub { \
+&aboutbox()       });

return $menubar;
}

sub aboutbox{

 my $about_box = $mw->DialogBox(-title => "About", -buttons => ["OK"])
+;
 $about_box->add('Label', -anchor  => 'w',
                          -justify => 'center',
                          -text => qq(
This Simple Calculator was created Feb. 2004 by Eoin Murphy.
It was completed with the help of http:\/\/www.perlmonks.com, and thei
+r 
wonderful members. JamesNC and zentara to mention a few who helped.))-
+>pack(qw/-side top -anchor w/);


 $about_box->add('Label', -anchor  => 'sw',
                          -justify => 'left',
                          -text => qq(
eoin
eoinmurphy00\@hotmail.com
http:\/\/eoin.perlmonk.org))->pack(qw/-side top -anchor sw/);

$about_box->Show();


}
Replies are listed 'Best First'.
Re: Simple Calculator using Tk
by Albannach (Prior) on Feb 20, 2004 at 01:53 UTC
    A neat little job ++! Also a good choice of application for GUI practice with lots of scope for growth (consider adding a 'paper tape' feature, or date calculations for instance).

    One minor thing (which bites me often too) - the generation of a bug via cut & paste. You duplicated the line to create all your menu commands, and consequently your Exit command is passed as a 'Q' button press. Unfortunately there is no 'Q' button, so the 'Q' is passed on to calc(), where it acts to clear the display and buffer.

    Update: To clarify, there is nothing fundamentally wrong with cut & paste code generation, as long as you are aware of and checking carefully for this type of error. However, if you find yourself needing many copies of the same line with very minor changes, sometimes it indicates that you should consider a different structure.

    --
    I'd like to be able to assign to an luser

      Damn, I should have spoted that 'Q' typo. The 'Q' should be passed as a key press instead of a button press. I'll update the code correcting that.

      Regarding the cut and paste aspect. I didn;t really think about doing it any other way. I suppose I could have now that you say it, but this is the quickest and easiest(although not always the right, as you pointed out) way to do this.

      Cheers, Eoin...
Re: Simple Calculator using Tk
by eoin (Monk) on Feb 19, 2004 at 18:02 UTC
    This is my first post so feel free to lay into me.
    It was hard to decide bwtween pack or grid for this. In the end I used pack. If you think grid would have been more sutible please let me know.
    All the best,
    Eoin
Re: Simple Calculator using Tk
by zentara (Archbishop) on Feb 20, 2004 at 17:00 UTC
    Looks nice. I would add some color though, to make the keys stand out. Maybe put a different color for the numbers, and function keys, and a separate one for =.

    I'm not really a human, but I play one on earth. flash japh
Re: Simple Calculator using Tk
by Elijah (Hermit) on Mar 05, 2004 at 21:10 UTC
    Nice program. I just have a few suggestions though and they are really just preference by me and not more functional one way or the other. I would remove the tearoff function of the drop down menus. I know for me I never use it and it just looks ugly with that line at the top of every drop down.

    Second I would not have the numbers dissapear before the next number is entered during a calculation. This could be achieved by maybe using a flag variable and set the flag when a calculation key is pressed and then when entering text check for the flag and if it has a value or a cetrtain value then clear before entering the text and if not then just append the text onto the existing number.

    Lastly there seems to be an error when using decimal points in calculations. It only allows 2 decimal places after the decimal point and it does not calculate sometimes.

    Other than those, good job!

Re: Simple Calculator using Tk
by Anonymous Monk on Feb 23, 2004 at 10:51 UTC
    Little typo in about section - change Feburary to Feb. by alfarid

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (5)
As of 2020-09-25 20:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    If at first I donít succeed, I Ö










    Results (141 votes). Check out past polls.

    Notices?