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 :
- we want to draw an object, so extends our
Object class
- 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
- give some random position to each stars,
- but we need to know "screen" size, so give width and heigth size in
BasicStar constructor
- each stars will have a random size
- 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 :
here are some details :
ChristmasWidget inherits from a basic graphical widget containg some drawing facilities not shown here.
$objects is an array where we will store our objects ; those objects must be drawables (should inherit from Object)
- in object model, we allway construct ourself with this method
- this widget will have some dynamic response, so create a timeout that will be called periodicaly
- at window creation or resize, this method is called ; now we are nearly ready for drawing ;
- empty current list of object ( or create a new one),
- parent widget hase some drawing capabilities, so let it do what is needed,
- we need to know our size
($w, $h) to display in full window,
- create a bunch of Star objects,
- number of star is proportional to window size,
- this timeout function is called every 350 ms and will allow some dynamics display (see note 4)
- this is a full redraw method
- a realized widget is a widget that is constructed and have a (system) window ; without window, we can't draw
- take our object list and,
- 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.
- 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 :
- we want to create a Widget from a
GtkWindow
- let Window creation,
- this will quit application when user close window,
- set window title,
- at window creation, set position a screen center,
- set window size to (600, 500) pixels
- add to window management an instance of our Christmas widget,
- show window, by default windows and their content are not displayed (mapped)
- create an instance of our
ChrismasDemo window class
- 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 :
- we know how to draw a basic star, so inherit from this class to build our
BlinkingStar,
$cycle, $step have been explained below,
- we have a predefined list of color in #rrggbb format, select a random value from this list,
- introduce an extra random cycle : will exit loop for 30% calls
$r is the last radius used when drawing at last call ; it will be used to clear star
- 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),
- change color luminence and chrominance.
Links
Recent comments
4 weeks 5 days ago
10 weeks 4 days ago
12 weeks 2 days ago
18 weeks 5 days ago
20 weeks 3 hours ago
20 weeks 1 day ago
21 weeks 2 days ago
22 weeks 1 day ago
32 weeks 6 days ago
33 weeks 13 hours ago