Chapter 21 – Graphics/Tk Outline 21.1 Introduction 21.2 GD Module: Creating Simple Shapes 21.3 GD Module: Image Manipulation 21.4 Chart Module 21.5 Introduction to GUI 21.6 Introduction to Tk 21.7 Tk: GUI Components 21.8 Tk Case Study: A GUI Application
21.1 Introduction Graphics Graphics in Perl Video games, billboards, movies Web pages Pictures used to provide information Graphics are not just pictures Colors, lines, patterns Graphics in Perl No graphics functions built-in Graphics modules allow graphic manipulation
21.2 GD Module: Creating Simple Shapes The GD module Used to create and manipulate images Like a paint program Done through text commands User does not draw directly
Creates the colors of the variable’s name 28 27 $polygon->addPt( 100, 175 ); 26 $polygon->addPt( 20, 175 ); 25 $polygon->addPt( 20, 300 ); 24 my $polygon = new GD::Polygon(); 23 22 $image->fillToBorder( 150, 110, $green, $green ); 21 $image->rectangle( 100, 100, 200, 125, $green ); 20 $image->fill( 200, 200, $blue ); 19 $image->arc( 200, 200, 50, 50, 0, 360, $black ); 18 $image->filledRectangle( 15, 15, 150, 150, $red ); 17 16 my $purple = $image->colorAllocate( 255, 0, 255 ); 15 my $black = $image->colorAllocate( 0, 0, 0 ); 14 my $blue = $image->colorAllocate( 0, 0, 255 ); 13 my $green = $image->colorAllocate( 0, 255, 0 ); 12 my $red = $image->colorAllocate( 255, 0, 0 ); 11 my $white = $image->colorAllocate( 255, 255, 255 ); 10 9 my $image = new GD::Image( 320, 320 ); 8 7 use GD; 6 use warnings; 5 use strict; 4 3 # Using the GD module to create shapes. 2 # Fig 21.1: fig21_01.pl 1 #!/usr/bin/perl fig21_01.pl Creates the colors of the variable’s name Creates a red square Creates a black circle and fills it blue Creates a green rectangle Creates a shape using the given points
Fills the polygon purple and makes it outlined in blue fig21_01.pl 42 print( PICT $image->png() ); 41 binmode( PICT ); 40 39 die( "Can not open picture: $!" ); 38 open( PICT, ">fig21_02.png" ) or 37 36 $image->filledPolygon( $polygon, $black ); 35 34 $polygon->setPt( 2, 110, 175 ); 33 $polygon->setPt( 1, 110, 300 ); 32 $polygon->setPt( 0, 30, 300 ); 31 30 $image->fill( 50, 200, $purple ); 29 $image->polygon( $polygon, $blue ); Fills the polygon purple and makes it outlined in blue fig21_01.pl Creates another polygon and fills it black Stores the picture to a file
21.2 GD Module: Creating Simple Shapes Fig. 21.2 Contents of fig21_02.png.
21.3 GD Module: Image Manipulation More of the GD module Image manipulation
Creates a new image from a .png file 23 close( FILE ) or die( "Can not close file: $!" ); 1 #!/usr/bin/perl 2 # Fig 21.3: fig21_03.pl 3 # A program to enlarge a picture. 4 5 use GD; 6 use strict; 7 use warnings; 8 9 my $image = GD::Image->newFromPng( "fig21_02.png" ); 10 my @dimensions = $image->getBounds(); 11 my @newDimensions = map( { $_ * 2 } @dimensions ); 12 13 my $newImage = new GD::Image ( @newDimensions ); 14 $newImage->copyResized( $image, 0, 0, 0, 0, @newDimensions, 15 @dimensions ); 16 17 open( FILE, ">fig21_04.png" ) or 18 die( "Could not write to file: $!" ); 19 20 binmode( FILE ); 21 print( FILE $newImage->png() ); 22 fig21_03.pl Creates a new image from a .png file Copies $image from point (0, 0) with specifications in @dimensions and creates a new image starting at (0, 0) with the @newDimensions Stores the new image in a file
21.3 GD Module: Image Manipulation Fig. 21.4 Contents of fig21_04.png.
21.4 Chart Module The Chart module Used to create custom charts and graphs Extended modules Chart::Lines Chart::Bars Chart::Points
Uses the Chart::Lines module 27 $line->png( $file, \@data ); 1 #!/usr/bin/perl 2 # Fig 21.5: fig21_05.pl 3 # Using the Chart module. 4 5 use strict; 6 use warnings; 7 use Chart::Lines; 8 9 my $line = new Chart::Lines(); 10 my $file = "fig21_06.png"; 11 my @labels = ( "first", "second" ); 12 my %colors = ( "dataset0" => [ 100, 100, 255 ], 13 "dataset1" => [ 255, 100, 100 ], 14 "background" => [ 150, 235, 200 ] ); 15 16 $line->set( "title" => "Test Chart", "x_label" => "letter" ); 17 $line->set( "y_label" => "number", "legend" => "left" ); 18 $line->set( "legend_labels" => \@labels, "colors" => \%colors ); 19 $line->set( "grey_background" => 0 ); 20 21 my @Xlabels = ( 'a', 'b', 'c', 'd' ); 22 my @dataset1 = ( 1, 2, 3, 4 ); 23 my @dataset2 = ( 2, 3, 5, 9 ); 24 25 my @data = ( \@Xlabels, \@dataset1, \@dataset2 ); 26 fig21_05.pl Uses the Chart::Lines module Sets up the basics for the graph; title, x label, y label, colors Sets up the value for the x label, as well as the data to be entered into the graph
21.4 Chart Module Fig. 21.6 Contents of fig21_06.png.
21.5 Introduction to GUI Tk GUI A GUI toolkit Use the Tk module Graphical User Interface Gives a program a distinctive look and feel Built with GUI components Object in which the user interacts with mouse or keyboard
21.6 Introduction to Tk Event-handler loop Window Loop in which program waits for user interaction (an event) Mouse click, key stroke, or any other wide variety MainLoop() When an event occurs the loop invokes a function as specified to handle the event Window The main Tk object Other objects placed in the window Example: A Web browser
Place the GUI components on the window 25 } 24 $main->destroy(); 23 { 22 sub destroy 21 20 MainLoop(); 19 18 $button->pack(); 17 $label->pack(); 16 15 $button->configure( -text => 'Exit', -command => \&destroy ); 14 $label->configure( -text => 'Look at me!' ); 13 12 my $button = $main->Button(); 11 my $label = $main->Label(); 10 9 my $main = new MainWindow(); 8 7 use Tk; 6 use strict; 5 use warnings; 4 3 # A simple Perl/Tk program. 2 # Fig 21.7: fig21_07.pl 1 #!/usr/bin/perl fig21_07.pl Create a new window Create a label Create a button Sets the text properties of both the label and the button as well as the command of the button Place the GUI components on the window Calls the MainLoop function to wait for an event to occur button label
21.7 Tk: GUI Components Listbox RadioButton Scale Displays a list of items which the user can select from RadioButton Offers choices Only one radio button can be selected at a time Scale A vertical or horizontal slider Its value can be set by dragging it to the appropriate location
Defines an array of strings that will be placed into a list box 30 29 my @colors = qw( grey brown black tan ); 28 $window->Label( -text => "Select a color:" )->pack(); 27 26 my $window = $main->Toplevel(); 25 my $color; 24 my $animal = $list->get( $list->curselection() ); 23 { 22 sub choose1 21 20 MainLoop(); 19 18 $list->pack(); 17 $list->bind( '<Double-1>' => \&choose1 ); 16 $list->insert( 'end', @animals ); 15 my $list = $main->Listbox(); 14 $main->Label( -text => "Select an animal:" )->pack(); 13 12 qw( aardvark baboon cheetah dog elephant yak zebu ); 11 my @animals = 10 9 our $main = new MainWindow(); 8 7 use Tk; 6 use warnings; 5 use strict; 4 3 # Perl/Tk program using GUI components. 2 # Fig 21.8: fig21_08.pl 1 #!/usr/bin/perl fig21_08.pl Defines an array of strings that will be placed into a list box Creates a label that asks the user to select an animal Creates a new list box and inserts the items from the array Gets the current selection from the list Creates a new top level window
Creates radio buttons for each of the colors in the array fig21_08.pl 59 58 } 57 pack(); 56 [ \&choose3, $animal, $color, \$value, $window ], )-> 55 -command => 54 $window->Button( -text => 'Choose', 53 52 '-variable' => \$value, )->pack(); 51 -showvalue => 1, 50 'Select a size in feet:', '-length' => 200, 49 '-label' => 48 '-from' => 0, '-to' => 100, '-tickinterval' => 20, 47 $window->Scale( '-orient' => 'horizontal', 46 45 my $window = $parent->Toplevel(); 44 $color = $$color; 43 my $value = 0; 42 my ( $animal, $color, $parent ) = @_; 41 { 40 sub choose2 39 38 } 37 [ \&choose2, $animal, \$color, $window ] )->pack(); 36 $window->Button( -text => 'Choose', -command => 35 34 } 33 -variable => \$color, -value => $_ )->pack(); 32 $window->Radiobutton( -text => $_, 31 foreach ( @colors ) { Creates radio buttons for each of the colors in the array fig21_08.pl Creates a button to choose the desired color Creates another top level window Creates a new scale that runs horizontal across the window Creates another button to choose the current scale setting
Creates the last window of the program 78 } 77 $main->destroy() 76 { 75 sub destroy 74 73 } 72 -command => \&destroy )->pack(); 71 $window->Button( -text => 'Done', 70 69 "It's size is $$value feet tall." )->pack(); 68 $window->Label( -text => 67 $window->Label( -text => "It's color is $color." )->pack(); 66 pack(); 65 $window->Label( -text => "Your animal is a $animal." )-> 64 63 my $window = $parent->Toplevel(); 62 my ( $animal, $color, $value, $parent ) = @_; 61 { 60 sub choose3 Creates the last window of the program fig21_08.pl Creates labels to show the output based on what the user selected This button is used to terminate the program
21.7 Tk: GUI Components listbox Fig. 21.9 Fig21_08.pl’s main window.
21.7 Tk: GUI Components radio buttons Fig. 21.10 Fig21_08.pl’s first top-level window.
21.7 Tk: GUI Components scale Fig. 21.11 Fig21_08.pl’s third window.
21.7 Tk: GUI Components Fig. 21.12 Fig21_08.pl’s final window.
21.8 Tk Case Study: A GUI Application Frames Used to group similar components Can help add to organization of the window
Creates the window for the program 29 28 } 27 command => [ \&number, $_ ] )->pack( -side => "left" ); 26 $frame->Button( text => $_, 25 my $frame = $frames[ int( ( $_ - 1 ) / 3 ) ]; 24 for ( 1 .. 9 ) { 23 22 my $frame5 = $calculator->Frame()->pack( -side => 'top' ); 21 my $frame4 = $calculator->Frame()->pack( -side => 'top' ); 20 19 } 18 $calculator->Frame()->pack( -side => 'top' ) ); 17 push( @frames, 16 for ( 1 .. 3 ) { 15 14 my @frames; 13 12 our $label = $calculator->Label( width => '21' )->pack(); 11 my $oldOperator = ''; 10 our ( $number1, $number2 ); 9 my $calculator = new MainWindow(); 8 7 use Tk; 6 use warnings; 5 use strict; 4 3 # GUI Calculator with Tk. 2 # Fig 21.13: fig21_13.pl 1 #!/usr/bin/perl fig21_13.pl Creates the window for the program This label is used to output the calculation to the user Creates three frames on the window used to organize it better Creates the nine number buttons
fig21_13.pl 30 $frame4->Button( text => 'Enter', 62 } 61 } 60 $number2 = 0; 59 if ( $oldOperator eq '=' ) { 58 57 $label->configure( text => $number1 ); 56 $number1 = $number1 ? $number1 . $digit : $digit; 55 my $digit = shift(); 54 { 53 sub number 52 51 MainLoop(); 50 49 command => [ \&calculate, '/' ] )->pack( -side => "left" ); 48 $frame5->Button( text => '/', 47 46 command => [ \&calculate, '*' ] )->pack( -side => "left" ); 45 $frame5->Button( text => '*', 44 43 command => [ \&calculate, '-' ] )->pack( -side => "left" ); 42 $frame5->Button( text => '-', 41 40 command => [ \&calculate, '+' ] )->pack( -side => "left" ); 39 $frame5->Button( text => '+', 38 37 command => [ \&calculate, 'cl' ] )->pack( -side => "left" ); 36 $frame4->Button( text => 'Clear', 35 34 command => [ \&number, 0 ] )->pack( -side => "left" ); 33 $frame4->Button( text => '0', 32 31 command => [ \&calculate, '=' ] )->pack( -side => "left"); 30 $frame4->Button( text => 'Enter', fig21_13.pl
95 94 } 93 $number2 /= $number1; 92 elsif ( $oldOperator eq '/' ) { 91 } 90 $number2 *= $number1; 89 elsif ( $oldOperator eq '*' ) { 88 } 87 $number2 -= $number1; 86 elsif ( $oldOperator eq '-' ) { 85 } 84 $number2 += $number1; 83 if ( $oldOperator eq '+' ) { 82 81 else { 80 } 79 clear(); 78 text => 'Error: Divide by zero.' ); 77 $label->configure( 76 if ( $oldOperator eq '/' && ( $number1 == 0 ) ) { 75 74 if ( $oldOperator ) { 73 72 elsif ( $operation eq '=' ) { 71 } 70 $label->configure( text => $number1 ); 69 clear(); 68 if ( $operation eq 'cl' ) { 67 66 my $operation = shift(); 65 { 64 sub calculate 63 fig21_13.pl Performs the correct mathematical operation based on the button the user pressed
fig21_13.pl 96 $number1 = 0; 97 $oldOperator = $operation; 126 } 125 $number2 /= $number1; 124 elsif ( $oldOperator eq '/' ) { 123 } 122 $number2 *= $number1; 121 elsif ( $oldOperator eq '*' ) { 120 } 119 $number2 -= $number1; 118 elsif ( $oldOperator eq '-' ) { 117 } 116 $number2 += $number1; 115 if ( $oldOperator eq '+' ) { 114 113 else { 112 } 111 clear(); 110 $label->configure( text => 'Error: Divide by zero' ); 109 if ( ( $oldOperator eq '/' ) && ( $number1 == 0 ) ) { 108 107 elsif ( $oldOperator ) { 106 } 105 } 104 $oldOperator = $operation; 103 $number1 = 0; 102 $number2 = $number1; 101 else { 100 } 99 } 98 $label->configure( text => $number2 ); 97 $oldOperator = $operation; 96 $number1 = 0; fig21_13.pl
fig21_13.pl 127 elsif ( $oldOperator eq '=' ) { 148 } 147 $oldOperator = ""; 146 $number1 = 0; 145 $number2 = 0; 144 { 143 sub clear 142 141 } 140 } 139 $oldOperator = $operation; 138 $number1 = 0; 137 $number2 = $number1; 136 else { 135 } 134 } 133 $label->configure( text => $number2 ); 132 $oldOperator = $operation; 131 $number1 = 0; 130 129 } 128 $number2 = $number1 || $number2; 127 elsif ( $oldOperator eq '=' ) { fig21_13.pl
fig21_13.pl Program Output