Problem
This is in response to the comments of Laurent from France with regards to creating round buttons with rollover effect.
We have created a round button with rollover effect in How to create a round button - Part 2?.
Laurent commented that the rollover effect can be achieved more easily with the use of GtkWidget::set_state()
.
This article shows you what the code will look like using GtkWidget::set_state()
as suggested by Laurent as shown below. Do take a look at the code. You will find the code is indeed cleaner and more elegant. Also, you'll find this method GtkWidget::set_state()
very useful in some of your applications.
Solution
- When setting the pixmap of the button with GtkStyle::bg_pixmap, we can define different pixmap for the different states:
NORMAL
,PRELIGHT
andACTIVE
. - NORMAL: when the button is in the normal, unclicked state
- PRELIGHT: when you move your mouse over the button
- ACTIVE: when you have clicked the button
- Once you have defined the pixmap for the different states, when you set the state of the button with GtkWidget::set_state(), the corresponding pixmap will be displayed automatically!
Sample Code
Note: The following image files are required by the sample code below. Please save a copy of the image files and put them in the same directory where you store the sample code.
button_rew1.png | |
button_rew2.png | |
button_play1.png | |
button_play2.png | |
button_ff1.png | |
button_ff2.png |
1 2 3 5 6 7 8 9 11 13 18 19 20 21 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 74 75 76 77 78 79 80 81 82 83 84 85 86 87 93 94 95 96 97 98 100 101 102 108 109 110 111 118 119 120 121 | <?php $window = new GtkWindow(); $window->set_size_request(400, 200); $window->connect_simple('destroy', array('Gtk','main_quit')); $vbox = new GtkVBox(); $window->add($vbox); // create a hbox to hold the buttons $vbox->pack_start($hbox = new GtkHBox()); $buttons2 = new RoundButtons($hbox, array( array('button_rew1.png', 'button_rew2.png'), array('button_play1.png', 'button_play2.png'), array('button_ff1.png', 'button_ff2.png'))); class RoundButtons { function RoundButtons($container, $buttons) { $button_id = 0; $this->button_count = count($buttons); foreach($buttons as $button_img) { $this->create_round_button($container, $button_id, $button_img[0], $button_img[1]); $this->button_state[$button_id] = 0; ++$button_id; } } function create_round_button($container, $button_id, $image0, $image1) { $pixbuf[0]=GdkPixbuf::new_from_file($image0); list($this->pixmap[$button_id][0], $this->mask[$button_id][0]) = $pixbuf[0]-> render_pixmap_and_mask(255); $pixbuf[1]=GdkPixbuf::new_from_file($image1); list($this->pixmap[$button_id][1], $this->mask[$button_id][1]) = $pixbuf[1]-> render_pixmap_and_mask(255); $eventbox = new GtkEventBox(); $this->eventbox[$button_id] = $eventbox; $eventbox->set_size_request(100, -1); $container->pack_start($eventbox, 0, 0); $style = $eventbox->get_style(); $style=$style->copy(); $style->bg_pixmap[Gtk::STATE_NORMAL] = $this->pixmap[$button_id][0]; // note 1 $style->bg_pixmap[Gtk::STATE_PRELIGHT] = $this->pixmap[$button_id][1]; // note 2 $style->bg_pixmap[Gtk::STATE_ACTIVE] = $this->pixmap[$button_id][1]; // note 3 $eventbox->set_style($style); $eventbox->shape_combine_mask($this->mask[$button_id][0], 0, 0); $eventbox->connect('button-press-event', array(&$this, 'on_button_press'), $button_id); $eventbox->connect('enter-notify-event', array(&$this, 'on_enter_leave'), $button_id, 1); $eventbox->connect('leave-notify-event', array(&$this, 'on_enter_leave'), $button_id, 0); } function on_button_press($widget, $event, $button_id) { echo "button_pressed: button $button_id!\n"; for ($i=0; $i<$this->button_count; ++$i) { $state = ($i==$button_id) ? Gtk::STATE_ACTIVE : Gtk::STATE_NORMAL; $this->eventbox[$i]->set_state($state); // note 4 $this->button_state[$i] = $state; } return true; } function on_enter_leave($widget, $event, $button_id, $enter_leave) { if ($enter_leave==0 && $this->button_state[$button_id]) return; $state = ($enter_leave) ? Gtk::STATE_PRELIGHT : Gtk::STATE_NORMAL; $widget->set_state($state); // note 5 return true; } } $window->show_all(); Gtk::main(); ?> |
Output
As shown above.Explanation
- Define the pixmap of the button for the NORMAL state.
- Define the pixmap of the button for the PRELIGHT state.
- Define the pixmap of the button for the ACTIVE state.
- When the user clicks a button, we set the state of the clicked button to
ACTIVE
and the unclicked buttons toNORMAL
. Note that the corresponding pixmap will be updated automatically. - When the mouse is over a button, we set the state of the corresponding button to
PRELIGHT
and the others toNORMAL
. When the mouse leaves a button, we set all buttons to stateNORMAL
. Note that the corresponding pixmap will be updated automatically.
Read more...