If you are a Gtk+ veteran, you may be familiar with the feeling of inferiority coming over you when using the Gtk2::FileSelection widget. This widget looked like a typical Tk design and was not very flexible.
Today we are blessed with the more functional and appealing Gtk2::FileChooser interface and the widgets making use of it. They are the Gtk2::FileChooserWidget, Gtk2::FileChooserDialog, and Gtk2::FileChooserButton.
This lesson will show the reader how to utilize these classes.
We create a simple program which shows the two types of Gtk2::FileChooserButtons. It also shows the effect that different values of the 'action' property have on the appearance of the Gtk2::FileChooserDialog.
Table 20-1. Gtk2 object classes used
Gtk2 Class Name |
|---|
Gtk2::Window |
Gtk2::VBox |
Gtk2::HBox |
Gtk2::Frame |
Gtk2::FileChooserButton |
Gtk2::FileChooserDialog |
Gtk2::Button |
Gtk2::MessageDialog |
The program can be found here: 'gtk2_file_chooser.pl'
1 #! /usr/bin/perl -w 2 3 use strict; 4 use Gtk2 '-init'; 5 use Glib qw/TRUE FALSE/; 6 7 #standard window creation, placement, and signal connecting 8 my $window = Gtk2::Window->new('toplevel'); 9 $window->signal_connect('delete_event' => sub { Gtk2->main_quit; }); 10 $window->set_border_width(5); 11 $window->set_position('center_always'); 12 13 #add and show the vbox 14 $window->add(&ret_vbox); 15 $window->show(); 16 17 #our main event-loop 18 Gtk2->main(); 19 20 sub ret_vbox { 21 22 my $vbox = Gtk2::VBox->new(FALSE,5); 23 24 #*************************************** 25 #Show the filechooserbuttons (open and select-folder action types) 26 my $frm_fl_chooser_button = Gtk2::Frame->new('Gtk2::FileChooserButton'); 27 $frm_fl_chooser_button->set_border_width(5); 28 29 my $hbox_fl_chooser_button = Gtk2::HBox->new(FALSE,5); 30 $hbox_fl_chooser_button->set_border_width(10); 31 32 #Open a file dialog button-----> 33 my $fc_btn_file =Gtk2::FileChooserButton->new ('select a file' , 'open'); 34 $fc_btn_file->set_filename("/etc/passwd"); 35 $hbox_fl_chooser_button->pack_start($fc_btn_file,TRUE,TRUE,6); 36 37 #Open a folder dialog button----> 38 my $fc_btn_folder =Gtk2::FileChooserButton->new ('select a folder' , 'select-folder'); 39 $hbox_fl_chooser_button->pack_start($fc_btn_folder,TRUE,TRUE,6); 40 41 $frm_fl_chooser_button->add($hbox_fl_chooser_button); 42 $vbox->pack_start($frm_fl_chooser_button,FALSE,FALSE,6); 43 44 #*************************************** 45 #Show the filechooserdialog action types (open save select-folder create-folder) 46 my $frm_fl_chooser_dialog = Gtk2::Frame->new('Gtk2::FileChooserDialog Incarnations'); 47 48 my $hbox_fl_chooser_dialog = Gtk2::HBox->new(FALSE,5); 49 $hbox_fl_chooser_dialog->set_border_width(10); 50 51 #Open----> 52 my $btn_open = Gtk2::Button ->new('_Open'); 53 $btn_open->signal_connect('clicked' => 54 sub{ show_chooser('File Chooser type open','open',ret_png_filter()) }); 55 $hbox_fl_chooser_dialog->pack_start($btn_open,TRUE,TRUE,6); 56 57 #Save----> 58 my $btn_save = Gtk2::Button->new('_Save'); 59 $btn_save->signal_connect('clicked' => 60 sub{ show_chooser('File Chooser type save','save') }); 61 $hbox_fl_chooser_dialog->pack_start($btn_save,TRUE,TRUE,6); 62 63 #Select Folder----> 64 my $btn_select_folder = Gtk2::Button->new('S_elect Folder'); 65 $btn_select_folder->signal_connect('clicked' => 66 sub{ show_chooser('File Chooser type select-folder','select-folder') }); 67 $hbox_fl_chooser_dialog->pack_start($btn_select_folder,TRUE,TRUE,6); 68 69 #Create Folder----> 70 my $btn_create_folder = Gtk2::Button->new('_Create Folder'); 71 $btn_create_folder->signal_connect('clicked' => 72 sub{ show_chooser('File Chooser type create-folder','create-folder') }); 73 $hbox_fl_chooser_dialog->pack_start($btn_create_folder,TRUE,TRUE,6); 74 75 $frm_fl_chooser_dialog->add($hbox_fl_chooser_dialog); 76 $vbox->pack_start($frm_fl_chooser_dialog,FALSE,FALSE,6); 77 78 79 $vbox->show_all(); 80 return $vbox; 81 } 82 83 sub show_chooser { 84 #--------------------------------------------------- 85 #Pops up a standard file chooser-------------------- 86 #Specify a header to be displayed------------------- 87 #Specify a type depending on your needs------------- 88 #Optionally add a filter to show only certain files- 89 #will return a path, if valid---------------------- 90 #--------------------------------------------------- 91 92 my($heading,$type,$filter) =@_; 93 #$type can be: 94 #* 'open' 95 #* 'save' 96 #* 'select-folder' 97 #* 'create-folder' 98 my $file_chooser = Gtk2::FileChooserDialog->new ( 99 $heading, 100 undef, 101 $type, 102 'gtk-cancel' => 'cancel', 103 'gtk-ok' => 'ok' 104 ); 105 (defined $filter)&&($file_chooser->add_filter($filter)); 106 107 #if action = 'save' suggest a filename 108 ($type eq 'save')&&($file_chooser->set_current_name("suggeste_this_file.name")); 109 110 my $filename; 111 112 if ('ok' eq $file_chooser->run){ 113 $filename = $file_chooser->get_filename; 114 print "filename $filename\n"; 115 } 116 117 $file_chooser->destroy; 118 119 if (defined $filename){ 120 if ((-f $filename)&&($type eq 'save')) { 121 my $overwrite =show_message_dialog( $window, 122 'question' 123 ,'Overwrite existing file:'."<b>\n$filename</b>" 124 ,'yes-no' 125 ); 126 return if ($overwrite eq 'no'); 127 } 128 return $filename; 129 } 130 return; 131 } 132 133 sub show_message_dialog { 134 #--------------------------------------------------- 135 #you tell it what to display, and how to display it 136 #$parent is the parent window, or "undef" 137 #$icon can be one of the following: a) 'info' 138 # b) 'warning' 139 # c) 'error' 140 # d) 'question' 141 #$text can be pango markup text, or just plain text, IE the message 142 #$button_type can be one of the following: a) 'none' 143 # b) 'ok' 144 # c) 'close' 145 # d) 'cancel' 146 # e) 'yes-no' 147 # f) 'ok-cancel' 148 #--------------------------------------------------- 149 150 my ($parent,$icon,$text,$button_type) = @_; 151 152 my $dialog = Gtk2::MessageDialog->new_with_markup ($parent, 153 [qw/modal destroy-with-parent/], 154 $icon, 155 $button_type, 156 sprintf "$text"); 157 my $retval = $dialog->run; 158 $dialog->destroy; 159 return $retval; 160 } 161 162 163 sub ret_png_filter { 164 #---------------------------------------- 165 #Returns a filter, filtering only png files 166 #---------------------------------------- 167 168 my $filter = Gtk2::FileFilter->new(); 169 $filter->set_name("Images"); 170 $filter->add_mime_type("image/png"); 171 172 return $filter; 173 }
The following widgets make use of the Gtk2::FileChooser interface: Gtk2::FileChooserDialog, Gtk2::FileChooserButton, Gtk2::FileChooserWidget.
This means that the methods and properties available to the Gtk2::FileChooser should also be available to these widgets.
Depending how the widget makes use of the Gtk2::FileChooser interface, it may enable / disable the use of certain properties. The 'set_current_name' method for instance can't be used if the 'action' property is set to 'open'.
The Gtk2::FileChooserButton can be constructed using a few methods. The one we use automatically creates a Gtk2::FileChooserDialog and associates it with the Gtk2::FileChooserButton.
![]() | Remember: The only actions |
Talking about 'set_current_name'. This is used to suggest a name when saving a file.
The Gtk2::FileChooser has a property 'do-overwrite-confirmation'. It seems that setting this to TRUE will ask for confirmation when a user selected a file already in existence. ('action' must also be equal to 'save')
The tests I've done could not get this working, thus in the sample program, when an existing file is chosen the yes/no question is invoked in code.
Rather than creating a Gtk2::FileChooserDialog each time you need one, it is good practice to have a sub that takes certain arguments to manipulate the appearance of the Gtk2::FileChooserDialog and return the value specified.
On the Gtk2::FileChooserDialog POD page, you will see the following: * ... (list) list of button-text => response-id pairs. This will typically be an 'ok' and 'cancel' button.
'gtk-cancel' => 'cancel', 'gtk-ok' => 'ok'
The Gtk2::FileChooserWidget was not used directly, but it is used inside the Gtk2::FileChooserDialog. You may use it on its own, but the Gtk2::FileChooserDialog is just way more convienient.
Adding a Gtk2::FileFilter to the Gtk2::FileChooser will let the Gtk2::FileChooser show only those file types we asked for.
Two methods are generally used to add a filetype to a Gtk2::FileFilter.
The recommended one is 'add_mime_type'. This will let the filechooser 'look into' a file, thus if you have a .png file without the .png eextension, it will still show when you specified the following:
$filter->add_mime_type("image/png");
The other method is 'add_pattern'. This method makes use of wild charts. Typical sample code will look as follows:
$filter->add_pattern("*.png");
$filter->add_pattern("*.jpg");
$filter->add_pattern("*.gif");
$filter->add_pattern("*.tif");
$filter->add_pattern("*.xpm");
$filter->add_pattern("*.bmp");
Note that they can be stacked!
With the addition of Gtk2::FileChooser to the newer versions of Gtk+, we finally do not have to be ashamed any more when asking someone to open or save a file in our program. Gtk2::FileChooser was dearly needed and is just as dearly appreciated!