17 feb. 2010 : PHP-GTK Application descriptions can now be submitted in Brazilian Portuguese too. Thanks Bruno Bandeira !.

German and Italian still missing: who will contribute the translated categories for these languages ? Contact the team to offer your translations !

Merry Christmas with php-gtk and object oriented software (tutorial).

drawing blinking stars with php-gtk It's time to have some fun for the holiday season. We are going to draw some stars in a Drawing Area. Stars will have random colors, and random blinking cycle. Will will try to write some object-oriented code to show good practices with php-gtk.

For basic introduction to object syntax please refer to official php site.

First, create a basic class with some properties :

  • this class will handle graphical objects with geometrical positions ($x, $y) and size ($w, $h) as width and height
  • we can't instanciate this class because it is useless ; so create it as abstract ; if you try $obj=new Object, php will complaint about this. (Fatal error: Cannot instantiate abstract class Object)
  • this is a graphical object, so we need to draw it, so create a draw() method as abstract because we can't draw anything now.
<?php
abstract class Object {
    protected
$x, $y, $w, $h;
    abstract public function
draw($drawing);
}
?>

Object Oriented design hints

when you create some classes :

  • allways create attributes as protected if you have no good reasons to make them private or public,
  • general usage methods will always be with public attribute visibility
  • some methods will exist for internal usage, there are protected methods, avaid private methods
  • unspecified methods will have public visibility
  • unspecified attributes will have public visibility to.

Let's go on

Now create a basic star with this piece of code : BasicStar class

  1. we want to draw an object, so extends our Object class
  2. for a star, we need a postion (Object properties), a color, and a radius for differents star sizes, so create all this atributes as protected members
  3. give some random position to each stars,
  4. but we need to know "screen" size, so give width and heigth size in BasicStar constructor
  5. each stars will have a random size
  6. a star knows how to draw itself in a drawing area (this is a drawable in php-gtk) ; a drawable can be a Window or a Buffer (pixmap). In this case, GtkDrawable has all needed primitives to make some drawings (lines, rectangles, circles ...). Here, we will use a GtkDrawingArea extention class to help drawing hiding some Gtk stuff (graphic context, colormap, event mask, pixmap, draw queue).
<?php
class BasicStar extends Object{     // note 1
   
protected $color;    // note 2
   
protected $radius// note 2

   
function __construct($w, $h){  // note 4
       
$this->color = 'yellow';
       
$this->x = rand(0, $w);   // note 3
       
$this->y = rand(0, $h);   // note 3
       
$this->radius = rand(1, 3);    // note 5
   
}

    function
draw($da){   // note 6
       
$da->draw_circle($this->color, $filled=true, $this->x-$this->radius, $this->y-$this->radius, $this->radius*2);
    }
}
?>

A Christmas Widget

Let's create a graphical widget than can handle :

  • drawing primitives from a drawing area
  • our BasicStar class

here are some details :

  1. ChristmasWidget inherits from a basic graphical widget containg some drawing facilities not shown here.
  2. $objects is an array where we will store our objects ; those objects must be drawables (should inherit from Object)
  3. in object model, we allway construct ourself with this method
  4. this widget will have some dynamic response, so create a timeout that will be called periodicaly
  5. at window creation or resize, this method is called ; now we are nearly ready for drawing ;
  6. empty current list of object ( or create a new one),
  7. parent widget hase some drawing capabilities, so let it do what is needed,
  8. we need to know our size ($w, $h) to display in full window,
  9. create a bunch of Star objects,
  10. number of star is proportional to window size,
  11. this timeout function is called every 350 ms and will allow some dynamics display (see note 4)
  12. this is a full redraw method
  13. a realized widget is a widget that is constructed and have a (system) window ; without window, we can't draw
  14. take our object list and,
  15. call foreach object draw() method ; objects can only draw on a DrawingArea ; ChristmasWidget inherits from DrawingArea, so $this is a DrawingiArea, so give it to graphical objects to render graphics.
  16. we are drawing in a Pixmap (double buffering cache); so we need to refresh Window content from Pixmap
<?php
class ChristmasWidget extends GraphCore// note 1

   
protected $objects;   // note 2

   
public function __construct(){
       
parent::__construct();   // note 3
       
$this->objects = array();  // note 2

       
Gtk::timeout_add(350, array($this, 'timeout'));  // note 4

   
}override this method and draw what you want.

    function
configure_event($widget, $event){  // note 5

       
$this->objects = array();   // note 6

       
parent::configure_event($widget, $event);  // note 6

       
$w = $this->w();  // note 7
       
$h = $this->h();

       
$count = intval(($w+$h)/10);  // note 9

       
for($i=0 ; $i<$count ; $i++)  // note 8
           
$this->objects[] = new BasicStar($w, $h);
    }

    public function
timeout(){  // note 10
       
$this->do_redraw();
        return
true;
    }

    function
do_redraw(){   // note 11

       
if(!$this->realized())  // note 12
           
return;

        foreach(
$this->objects as $obj){ // note 13
           
$obj->draw($this);
        }

       
$this->refresh();   // note 14
   
}
}
?>

ChrismasDemo window

Here every things is object, so let's create a new Window dedicated for our Christmas application demonstration. Here are all details :

  1. we want to create a Widget from a GtkWindow
  2. let Window creation,
  3. this will quit application when user close window,
  4. set window title,
  5. at window creation, set position a screen center,
  6. set window size to (600, 500) pixels
  7. add to window management an instance of our Christmas widget,
  8. show window, by default windows and their content are not displayed (mapped)
  9. create an instance of our ChrismasDemo window class
  10. and enter in event loop
<?php
class ChrismasDemo extends GtkWindow//note 1

   
function __construct(){
       
parent::__construct();  // note 2

       
$this->connect_simple('destroy', array('gtk', 'main_quit'));  // note 3
       
$this->set_title('Merry Christmas');  // note 4
       
$this->set_position(Gtk::WIN_POS_CENTER);  // note 5
       
$this->set_size_request(600, 500);  // note 6

       
$this->add (new ChristmasWidget()); // note 7

       
$this->show_all(); // note 8
   
}
}

$demo = new ChrismasDemo(); // note 9

Gtk::main(); // note 10
?>

Blinking Star

To make our stars blink, we need :

  • a sort of counter (step) ; each time we call draw() method, this counter will grow up,
  • here we will change star radius, it will be beter to change color luminence ; I don't know how to
  • we will have differents colors near red, blue and yellow,
  • each stars will have their own blinking cycle
  • $color and $radius attributes are inherited from BasicStar, so we don't need to declare them again here ; if you do that that will not make some damages just consume some memory.

Some details :

  1. we know how to draw a basic star, so inherit from this class to build our BlinkingStar,
  2. $cycle, $step have been explained below,
  3. we have a predefined list of color in #rrggbb format, select a random value from this list,
  4. introduce an extra random cycle : will exit loop for 30% calls
  5. $r is the last radius used when drawing at last call ; it will be used to clear star
  6. give a value to radius star that will change with $step value (modulo) ; avaid a 0 radius
<?php
class BlinkingStar extends BasicStar{   // note 1
   
protected $cycle;   // note 2
   
protected $step;
    protected
$colors = array(
          
'#fff589', '#f5ff89', '#fff089', '#b7b7ff',
          
'#fff589', '#f5ff89' ,'#f8debc');  // note 3

   
function __construct($w, $h){
       
parent::__construct($w, $h);
       
$this->color = $this->colors[rand(0, count($this->colors)-1)];  // note 3
       
$this->cycle = rand(20, 50);
       
$this->step = rand(0, $this->cycle);
    }

    function
draw($da){

       
# introduce some random delay
       
if(rand(0, 10) > 3// note 4
           
return;

        if(isset(
$this->r)){   // note 5
           
$r = $this->r;
           
# clear star area
           
$da->draw_circle('black', $filled=true,
                            
$this->x-$r, $this->y-$r, $r*2);  // note 5
       
}

       
# draw a star with a radius changing step by step
       
$r = $this->step % $this->radius+1// note 6
       
$da->draw_circle($this->color, $filled=true, $this->x-$r, $this->y-$r, $r*2);  // note 6
       
$this->r = $r;

       
$this->step++;
    }
}
?>

Source code

You can get complete source code in attachment at the bottom of this page.

Conclusions

With object oriented design you can see how it is very easy to create some basics objects and extends them. With php-gtk you can make some graphical application : games, animation, simulations, map drawing, vector drawing. Object oriented design is really interesting with graphical features.

In this tutorial, we have created some graphicals objects with dedicated classes ; theses objects are managed with specialized widget ChristmasWidget and for completeness we have created our ChristmasWindow widget. Here is some details :

  • ChristmasWidget don't know how to draw a star, this widget task is only to manage a collection of graphical objects and call draw() method,
  • graphical objects don't know any thing about application, they only draw them self to a drawable object,

Todo

  • draw a nice a big moon that will move on the sky (look at php script example below), moon class demo
  • change color luminence and chrominance.

Links

AttachmentSize
Star tutorial source code5.35 KB
Star tutorial with moon class5.58 KB