Problem
As I've mentioned in my blog article titled "Some problems with GtkAssistant", currently the 'apply' signal and the method set_forward_page_func() are not working properly yet. This means that it's difficult for you to set up anything useful yet using GtkAssistant.
After playing with GtkAssistant for a while, I thought all the functionalities provided by this new widget can be reproduced exactly using GtkDialog.
So here it is — the same wizard reproduced using just plain old GtkDialog!
Since this uses only GtkDialog and not GtkAssistant, you can run the sample code below using any php-gtk2 without gtk+2.10 (yes, the Gnope version too).
Note that using this version, we're now able to grab the information entered in Step 1 (the name and email) to be used in the final step as shown below.
Solution
The code looks long, but it's actually very straightforward.
- The rectangle frame is constructed using a GtkFrame.
- The title comprises a GtkLabel stuffed inside a GtkEventBox with a blue background.
- Maybe the only "tricky" part is the swapping in and out of the pages.
- Each page is just a GtkVBox stored in the array $page[$page_num].
- When the user clicks the Next button, we remove the old page from the container ($page_vbox), and swap in the vbox containing the new page.
- Note that the method GtkContainer::remove() just remove the link from the container. The contents of all the pages remain intact in the memory. It's just hidden.
- The same goes with the three GtkButtons at the bottom. We hide and show them according to which page the user is currently on.
- The global variable
$current_page
keeps track of the current page the user is on. - In the event handler
on_button()
, we can also perform actions depending on which page the user is on. For example, in this example, we retrieve the name and email entered by the user when the user clicks on the Next button on page 1.
Sample Code
1 2 3 4 7 8 9 10 11 12 13 15 16 17 18 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 42 43 44 45 47 48 49 50 54 55 56 57 59 60 61 62 66 68 69 70 71 72 73 78 79 86 87 88 89 90 91 92 93 95 97 98 99 100 101 102 103 104 105 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 148 149 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | <?php // create a new dialog $dialog = new GtkDialog('Alert', null, Gtk::DIALOG_MODAL); // create a new dialog $dialog->set_title($argv[0]); $dialog->set_size_request(400,300); // create a frame with blue border $frame = new GtkFrame(); $frame->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse("#08216B")); $frame->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#08216B")); $frame->modify_base(Gtk::STATE_NORMAL, GdkColor::parse("#08216B")); $dialog->vbox->pack_start($frame); // create the title box with blue background $eventbox = new GtkEventBox(); $eventbox->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse("#08216B")); $title = new GtkLabel('Create New Account'); $title->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#ffffff")); $title->modify_font(new PangoFontDescription("Bold 14")); $title->set_size_request(-1, 40); $alignment = new GtkAlignment(0, 0.5, 0.04, 0.04); $alignment->add($title); $eventbox->add($alignment); $top_area = new GtkVBox(); $frame->add($top_area); $top_area->pack_start($eventbox, 0); // create the content area for each page $page_vbox = new GtkVBox(); $top_area->pack_start($page_vbox); $top_area->pack_start(new GtkLabel()); //intro $page[0] = new GtkVBox(); $page[0]->pack_start(new GtkLabel( "This wizard will help you create a new account.\n\n". "Creating a new account is just a two-step process.\n\n". "Click the Next button to start getting a free email account.")); $page[0]->show_all(); //Step 1 $page[1] = new GtkVBox(); $page[1]->pack_start(new GtkLabel("Please enter your name and email, \n". "and click Next")); $name_entry = setup_textentry($page[1], 'Name: '); $email_entry = setup_textentry($page[1], 'Email: '); $page[1]->show_all(); //Step 2 $page[2] = new GtkVBox(); $page[2]->pack_start(new GtkLabel("This is Step 2.")); $page[2]->show_all(); //Done $page[3] = new GtkVBox(); $page3_text = new GtkLabel(); $page[3]->pack_start($page3_text); $page[3]->show_all(); // start with the first page $page_vbox->pack_start($page[0], 1); $current_page = 0; // set up the buttons $hbox = new GtkHBox(); $hbox->pack_start(new GtkLabel()); $button_back = create_button($hbox, Gtk::STOCK_GO_BACK, 'Back'); $button_next = create_button($hbox, Gtk::STOCK_GO_FORWARD, 'Next'); $button_close = create_button($hbox, Gtk::STOCK_CLOSE, 'Close'); $dialog->vbox->pack_start(new GtkVBox(), 0); $dialog->vbox->pack_start($hbox, 0); $dialog->set_has_separator(false); $dialog->action_area->set_size_request(-1, 1); $dialog->show_all(); $button_back->hide(); $button_close->hide(); $button_next->grab_focus(); // all set! let's go! $dialog->run(); $dialog->destroy(); function setup_textentry($container, $label) { $hbox = new GtkHBox(); $hbox->pack_start(new GtkLabel($label), 0); $entry = new GtkEntry(); $hbox->pack_start($entry, 0); $container->pack_start($hbox, 0); return $entry; } function on_button($button, $label) { global $page_vbox, $current_page, $page; global $button_back, $button_next, $button_close; if ($label=='Close') { global $dialog; $dialog->destroy(); return; } global $name_entry, $email_entry; global $name, $email; if ($current_page==1) { $name = $name_entry->get_text(); // note 5 $email = $email_entry->get_text(); // note 5 echo "name = $name\n"; echo "email = $email\n"; } $button_back->hide(); $button_next->hide(); $button_close->hide(); if ($label=='Next') { $page_vbox->remove($page[$current_page]); // note 1 if ($current_page<3) ++$current_page; // note 2 } elseif ($label=='Back') { $page_vbox->remove($page[$current_page]); if ($current_page>0) --$current_page; } echo "new current_page = $current_page\n"; $page_vbox->pack_start($page[$current_page], 0); // note 3 $page[$current_page]->show_all(); global $title; switch($current_page) { // note 4 case 0: $title->set_text('Create New Account'); break; case 1: $title->set_text('Step 1 of 2'); break; case 2: $title->set_text('Step 2 of 2'); break; case 3: $title->set_text('Done'); break; } if ($current_page==count($page)-1) { $button_close->show(); $button_close->grab_focus(); global $page3_text; $page3_text->set_text("Congratulations, $name!\n\n". // note 6 "Your new account has been successfully created.\n\n". "A confirmation email has been sent to: $email"); } else { if ($current_page<(count($page)-1)) $button_next->show(); if ($current_page>0) $button_back->show(); } } function create_button($container, $stock_id, $label='', $width=82, $height=32) { if ($label=='') { return GtkButton::new_from_stock($stock_id); } $button = new GtkButton(); $hbox = new GtkHBox(); $button->add($hbox); $hbox->pack_start(new GtkLabel()); $img=GtkImage::new_from_stock($stock_id, Gtk::ICON_SIZE_SMALL_TOOLBAR); $hbox->pack_start($img, 0, 0); $hbox->pack_start(new GtkLabel(), 0, 0); $hbox->pack_start(new GtkLabel($label), 0, 0); $button->connect('clicked', 'on_button', $label); $button->set_size_request($width, $height); $container->pack_start($button, 0); $hbox->pack_start(new GtkLabel()); return $button; } ?> |
Output
As shown above.Explanation
Note that we make use of the technique as outlined in the article How to use stock images for buttons but with different labels - Part 1? to display buttons that use stock images but with different labels.
What's new here:
- Swap out the old page.
- If the user clicks the Next button, we increment the page counter.
- Swap in the new page.
- Set the page title depending on which page the user is on.
- For Step 1, we grab the name and email from the user input.
- Note how we displayed the name and email on this page using the user inputs the user entered in Step 1.
Note
You'll probably find this version much more "powerful" and flexible than using GtkAssistant as you have now control over every single widget in the wizard. For example, note that we have changed the label of the Forward button to "Next". At least for now, it's not possible for you to change the button label if you are using GtkAssistant.
More details in the blog article titled Implementing the GtkAssistant using GtkDialog.
Read more...