Here's my first attempt at a calculator written in perl. I've been using Tk for a long time, but recently I discovered PerlQt. What's nice about PerlQt is that it allows layouts to be designed in the QT Designer program with the aid of the pqt-designer plugin.
I did the basic layout in pqt designer, which let me set up the geometry and colors easily, and figure out which functions were availible for each widget. I don't know anything about calculator design, so this implementation may be a bit naive, but it came together pretty nicely. The look is patterned after the version of kcalc that comes with mandrake 10.0.
After I had the look set up I used another pqt tool called puic to transform the .ui file from QtDesigner into a perl script. I added all of the event handlers and the Buffer class by hand in vim
There are probably bugs. For one thing it does not properly format long number strings to fit in the display window. Also it only catches and ignore divide by zero errors, it doesn't send an error message to the display. Also to enter numbers that begin with a decimal point you must press Key_0 followed by Key_Decimal. And worst of all no -/+ toggle yet.
I figured i'd put it up anyhow, since I don't see that many programs written in Perl Qt, and I found it a bit easier to use than Tk or Wx
Any comments are welcome
#!/usr/bin/perl use strict; use utf8; package Buffer; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = { LEFT => undef, RIGHT => undef, MEMORY => undef, OP => undef, RESET => 0 }; bless( $self, $class ); return $self; } sub left { my $self = shift; if (@_) { $self->{LEFT} = shift; } return $self->{LEFT}; } sub right { my $self = shift; if (@_) { $self->{RIGHT} = shift; } return $self->{RIGHT}; } sub op { my $self = shift; if (@_) { my $op = shift; if ( $op =~ /^[+-\/*]$/ ) { $self->{OP} = $op; } } return $self->{OP}; } sub reset_display { my $self = shift; if (@_) { $self->{RESET} = shift; } return $self->{RESET}; } sub clear_all { my $self = shift; $self->{LEFT} = undef; $self->{RIGHT} = undef; $self->{OP} = undef; $self->{MEMORY} = undef; $self->reset_display(0); } 1; package PerlCalc; use Qt; use Qt::isa qw(Qt::Dialog); use Qt::slots Key_0_clicked => [], Key_1_clicked => [], Key_2_clicked => [], Key_3_clicked => [], Key_4_clicked => [], Key_5_clicked => [], Key_6_clicked => [], Key_7_clicked => [], Key_8_clicked => [], Key_9_clicked => [], Key_Clear_clicked => [], Key_Plus_clicked => [], Key_Minus_clicked => [], Key_Divide_clicked => [], Key_Times_clicked => [], Key_Equals_clicked => [], Key_Decimal_clicked => []; use Qt::attributes qw( Key_Divide Key_Clear Key_Decimal Key_Minus Key_Plus Key_1 Key_2 Key_3 Key_4 Key_5 Key_6 Key_7 Key_8 Key_9 Key_0 Key_Times Display Display_font Key_Equals ); our ($buffer) = Buffer->new(); sub NEW { shift->SUPER::NEW( @_[ 0 .. 3 ] ); if ( name() eq "unnamed" ) { setName("PerlCalc"); } Key_Divide = Qt::PushButton( this, "Key_Divide" ); Key_Divide->setGeometry( Qt::Rect( 90, 100, 51, 41 ) ); Key_Clear = Qt::PushButton( this, "Key_Clear" ); Key_Clear->setGeometry( Qt::Rect( 30, 100, 51, 41 ) ); Key_Decimal = Qt::PushButton( this, "Key_Decimal" ); Key_Decimal->setGeometry( Qt::Rect( 150, 300, 51, 41 ) ); Key_Minus = Qt::PushButton( this, "Key_Minus" ); Key_Minus->setGeometry( Qt::Rect( 210, 100, 51, 41 ) ); Key_Plus = Qt::PushButton( this, "Key_Plus" ); Key_Plus->setGeometry( Qt::Rect( 210, 151, 51, 90 ) ); Key_Times = Qt::PushButton( this, "Key_Times" ); Key_Times->setGeometry( Qt::Rect( 150, 100, 51, 41 ) ); Key_Equals = Qt::PushButton( this, "Key_Equals" ); Key_Equals->setGeometry( Qt::Rect( 210, 250, 51, 90 ) ); Key_0 = Qt::PushButton( this, "Key_0" ); Key_0->setGeometry( Qt::Rect( 30, 300, 110, 41 ) ); Key_1 = Qt::PushButton( this, "Key_1" ); Key_1->setGeometry( Qt::Rect( 30, 250, 51, 41 ) ); Key_2 = Qt::PushButton( this, "Key_2" ); Key_2->setGeometry( Qt::Rect( 90, 250, 51, 41 ) ); Key_3 = Qt::PushButton( this, "Key_3" ); Key_3->setGeometry( Qt::Rect( 150, 250, 51, 41 ) ); Key_4 = Qt::PushButton( this, "Key_4" ); Key_4->setGeometry( Qt::Rect( 30, 200, 51, 41 ) ); Key_5 = Qt::PushButton( this, "Key_5" ); Key_5->setGeometry( Qt::Rect( 90, 200, 51, 41 ) ); Key_6 = Qt::PushButton( this, "Key_6" ); Key_6->setGeometry( Qt::Rect( 150, 200, 51, 41 ) ); Key_7 = Qt::PushButton( this, "Key_7" ); Key_7->setGeometry( Qt::Rect( 30, 150, 51, 41 ) ); Key_8 = Qt::PushButton( this, "Key_8" ); Key_8->setGeometry( Qt::Rect( 90, 150, 51, 41 ) ); Key_9 = Qt::PushButton( this, "Key_9" ); Key_9->setGeometry( Qt::Rect( 150, 150, 51, 41 ) ); Display = Qt::Label( this, "Display" ); Display->setGeometry( Qt::Rect( 30, 20, 280, 51 ) ); Display->setBackgroundMode( &Qt::Label::PaletteBrightText() ); Display->setPaletteForegroundColor( Qt::Color( 255, 0, 0 ) ); Display->setPaletteBackgroundColor( Qt::Color( 0, 0, 0 ) ); my $Display_font = Qt::Font( Display->font ); $Display_font->setFamily("Monospace"); $Display_font->setPointSize(26); Display->setFont($Display_font); Display->setFrameShape( &Qt::Label::WinPanel() ); Display->setFrameShadow( &Qt::Label::Sunken() ); Display->setLineWidth( int(1) ); Display->setAlignment( int( &Qt::Label::AlignVCenter | &Qt::Label::AlignRight ) ); languageChange(); my $resize = Qt::Size( 327, 391 ); $resize = $resize->expandedTo( minimumSizeHint() ); resize($resize); clearWState(&Qt::WState_Polished); Qt::Object::connect( Key_0, SIGNAL "clicked()", this, SLOT "Key_0_clicked()" ); Qt::Object::connect( Key_1, SIGNAL "clicked()", this, SLOT "Key_1_clicked()" ); Qt::Object::connect( Key_2, SIGNAL "clicked()", this, SLOT "Key_2_clicked()" ); Qt::Object::connect( Key_3, SIGNAL "clicked()", this, SLOT "Key_3_clicked()" ); Qt::Object::connect( Key_4, SIGNAL "clicked()", this, SLOT "Key_4_clicked()" ); Qt::Object::connect( Key_5, SIGNAL "clicked()", this, SLOT "Key_5_clicked()" ); Qt::Object::connect( Key_6, SIGNAL "clicked()", this, SLOT "Key_6_clicked()" ); Qt::Object::connect( Key_7, SIGNAL "clicked()", this, SLOT "Key_7_clicked()" ); Qt::Object::connect( Key_8, SIGNAL "clicked()", this, SLOT "Key_8_clicked()" ); Qt::Object::connect( Key_9, SIGNAL "clicked()", this, SLOT "Key_9_clicked()" ); Qt::Object::connect( Key_Clear, SIGNAL "clicked()", this, SLOT "Key_Clear_clicked()" ); Qt::Object::connect( Key_Plus, SIGNAL "clicked()", this, SLOT "Key_Plus_clicked()" ); Qt::Object::connect( Key_Minus, SIGNAL "clicked()", this, SLOT "Key_Minus_clicked()" ); Qt::Object::connect( Key_Divide, SIGNAL "clicked()", this, SLOT "Key_Divide_clicked()" ); Qt::Object::connect( Key_Times, SIGNAL "clicked()", this, SLOT "Key_Times_clicked()" ); Qt::Object::connect( Key_Equals, SIGNAL "clicked()", this, SLOT "Key_Equals_clicked()" ); Qt::Object::connect( Key_Decimal, SIGNAL "clicked()", this, SLOT "Key_Decimal_clicked()" ); } # Sets the strings of the subwidgets using the current # language. sub languageChange { setCaption( trUtf8("PerlCalc") ); Key_Divide->setText( trUtf8("/") ); Key_Clear->setText( trUtf8("C") ); Key_Decimal->setText( trUtf8(".") ); Key_Minus->setText( trUtf8("-") ); Key_Plus->setText( trUtf8("+") ); Key_6->setText( trUtf8("6") ); Key_9->setText( trUtf8("9") ); Key_8->setText( trUtf8("8") ); Key_4->setText( trUtf8("4") ); Key_7->setText( trUtf8("7") ); Key_5->setText( trUtf8("5") ); Key_Times->setText( trUtf8("X") ); Key_1->setText( trUtf8("1") ); Display->setText( trUtf8("0") ); Key_Equals->setText( trUtf8("=") ); Key_0->setText( trUtf8("0") ); Key_2->setText( trUtf8("2") ); Key_3->setText( trUtf8("3") ); } sub Key_0_clicked { AppendDisplay("0"); } sub Key_1_clicked { AppendDisplay("1"); } sub Key_2_clicked { AppendDisplay("2"); } sub Key_3_clicked { AppendDisplay("3"); } sub Key_4_clicked { AppendDisplay("4"); } sub Key_5_clicked { AppendDisplay("5"); } sub Key_6_clicked { AppendDisplay("6"); } sub Key_7_clicked { AppendDisplay("7"); } sub Key_8_clicked { AppendDisplay("8"); } sub Key_9_clicked { AppendDisplay("9"); } sub Key_Divide_clicked { SetOp("/"); } sub Key_Minus_clicked { SetOp("-"); } sub Key_Times_clicked { SetOp("*"); } sub Key_Plus_clicked { SetOp("+"); } sub Key_Decimal_clicked { AppendDisplay("."); } sub Key_Clear_clicked { $buffer->clear_all; Display->setText("0"); } sub Key_Equals_clicked { my $left = $buffer->left; my $right = $buffer->right; my $result; SWITCH: for ( $buffer->op ) { /^[+]$/ && do { $result = $left + $right; last; }; /^[-]$/ && do { $result = $left - $right; last; }; /^[*]$/ && do { $result = $left * $right; last; }; /^[\/]$/ && do { eval { $result = $left / $right;}; warn $@ if $@; last; } } if ( $result =~ /^-?\d+\.?\d+$/ ) { $buffer->left($result); $buffer->reset_display(1); Display->setText($result); } } sub AppendDisplay { my $character = shift; my $text = Display->text; if ( $character eq '.' ) { return if $text =~ /\./; } Display->setText( $text && !$buffer->reset_display ? $text . $character : $character ); $buffer->reset_display(0); if ( !defined $buffer->op ) { $buffer->left( Display->text ); print STDERR "buffer left =" . $buffer->left . "\n"; } else { $buffer->right( Display->text ); print STDERR "buffer right =" . $buffer->right . "\n"; } } sub SetOp { my $op = shift; $buffer->op($op); $buffer->reset_display(1); } 1; package main; use Qt; use PerlCalc; my $a = Qt::Application( \@ARGV ); my $w = PerlCalc; $a->setMainWidget($w); $w->show; exit $a->exec;
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: A PerlQt Calculator
by thunders (Priest) on Jun 23, 2004 at 14:58 UTC | |
|
Re: A PerlQt Calculator
by Plankton (Vicar) on Jun 23, 2004 at 06:47 UTC | |
by thunders (Priest) on Jun 23, 2004 at 14:34 UTC |