Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 37 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
37
Dung lượng
792,02 KB
Nội dung
CHAPTER 12 ■ ADDING IMAGES258 Figure 12-1. A broken image icon Using a Stock ID In previous examples, you have seen how to create images for buttons and menu items by using stock IDs. A stock ID is a shortcut that identifies a commonly used image. You can also create a regular image from a stock ID by using new_from_stock. This static constructor takes the stock ID plus a size. The size is defined by a GtkIconSize constant. Stock images come in different sizes so that they can be used for different purposes. Each use has its own size constant, as follows: • Gtk::ICON_SIZE_MENU: A small image normally used in menus. • Gtk::ICON_SIZE_SMALL_TOOLBAR: A small version of the icon used for toolbars. • Gtk::ICON_SIZE_LARGE_TOOLBAR: A larger version of the toolbar icon. • Gtk::ICON_SIZE_BUTTON: The version normally used for buttons. • Gtk::ICON_SIZE_DND: The icon size used when an item is dragged. • Gtk::ICON_SIZE_DIALOG: The version normally used in dialog windows. Using a Pixel Buffer Another way to create an image is from data in memory. An image stored in memory can usu- ally be found in a GdkPixbuf. A pixel buffer (or pixbuf ) is simply a representation of the image in memory. It cannot be displayed on its own; it is just data. You can put an image into a pixbuf when an application is started to allow commonly used images to be loaded more quickly. A pixbuf can be created from a file, just as an image can be created. To create a pixbuf from a file, call the static constructor new_from_file and pass a file path. Listing 12-1 creates a pixbuf from a file and then creates an image from the pixbuf using the static constructor new_from_pixbuf. Listing 12-1. Loading an Image into a GdkPixbuf and Then a GtkImage <?php // Create a window to display the image. $window = new GtkWindow(); // Close the application cleanly. $window->connect_simple('destroy', array('Gtk', 'main_quit')); // Load a pixbuf from a file. $pb = GdkPixbuf::new_from_file('Crisscott/images/logo.png'); 6137ch12.qxd 3/14/06 2:29 PM Page 258 CHAPTER 12 ■ ADDING IMAGES 259 // Create the image from the pixbuf. $image = GtkImage::new_from_pixbuf($pb); // Add the image to the window. $window->add($image); // Show the image and the window. $window->show_all(); // Start the main loop. Gtk::main(); ?> Using GdkPixbuf and GtkImage, we can now add product images to the Crisscott PIMS application. Product images should appear in two places: in the product summary area and in the product editing tool. Listing 12-2 shows the code added to the Crisscott_Tools_ProductEdit class to allow the user to add or change a product image. The added lines include a GtkEntry for entering the path to the image file and the code to display the images. In this example, the creation of the pixbuf is wrapped in a try/catch block. That is because if the file for the pixbuf is not found, an excep- tion will be thrown. This allows the application to detect a failure to load an image. Listing 12-2. Adding Product Images to the Application <?php // The added lines from the product summary area. class Crisscott_Tools_ProductSummary extends GtkTable { // public function displaySummary(Crisscott_Product $product) { // Set the product. $this->product = $product; // Set the attribute labels to the values of the product. $this->productName->set_text($product->name); $this->productType->set_text($product->type); // Get the category information. require_once 'Crisscott/Inventory.php'; $inv = Crisscott_Inventory::singleton(); $cat = $inv->getCategoryById($product->categoryId); // Set the category name. $this->productCategory->set_text($cat->name); // Set the product price. $this->productPrice->set_text($product->price); // Remove the current product image. $this->productImage->remove($this->productImage->get_child()); 6137ch12.qxd 3/14/06 2:29 PM Page 259 CHAPTER 12 ■ ADDING IMAGES260 // Try to add the product image. try { // Create a pixbuf. $pixbuf = GdkPixbuf::new_from_file($product->imagePath); // Create an image from the pixbuf. $this->productImage->add(GtkImage::new_from_pixbuf($pixbuf)); // Show the image. $this->productImage->show_all(); } catch (Exception $e) { // Just fail silently. } } // } class Crisscott_Tools_ProductEdit extends GtkTable { // private function _layout() { // Set up the data entry widgets. // $this->imageContainer = new GtkFrame(); $this->imagePathEntry = new GtkEntry(); // // Set up the labels. // $this->imageLabel = new GtkLabel('Image'); // Set the labels' size. // $this->imageLabel->set_size_request(100, -1); // // Next align each label within the parent container. // $this->imageLabel->set_alignment(0, .5); // Make all of the labels use markup. // $this->imageLabel->set_use_markup(true); // 6137ch12.qxd 3/14/06 2:29 PM Page 260 CHAPTER 12 ■ ADDING IMAGES 261 // Attach the image widgets. $this->attachWithAlign($this->imageContainer, 2, 4, 0, 4, Gtk::FILL, 0); $this->attachWithAlign($this->imageLabel, 2, 4, 4, 5, Gtk::FILL, 0); $this->attachWithAlign($this->imagePathEntry, 3, 4, 4, 5, Gtk::FILL, 0); // } public function resetProduct() { // Make sure that there is a product. if (!isset($this->product)) { require_once 'Crisscott/Product.php'; $this->product = new Crisscott_Product(); } // Update the tools in the widget. // $this->imagePathEntry->set_text($this->product->imagePath); // Remove the current image. $this->imageContainer->remove($this->imageContainer->get_child()); // Try to load the product image. try { // Load the image into a pixbuf. $pixbuf = GdkPixbuf::new_from_file($this->product->imagePath); // Load the pixbuf into an image. $this->imageContainer->add(GtkImage::new_from_pixbuf($pixbuf)); // Show the image. $this->imageContainer->show_all(); } catch (Exception $e) { // Fail silently. // The product object will verify if the image exists. } // } } ?> Figure 12-2 shows the new version of the application. In Chapter 14, we will expand on this even further to make it easier to find a valid file path. 6137ch12.qxd 3/14/06 2:29 PM Page 261 CHAPTER 12 ■ ADDING IMAGES262 Figure 12-2. Product images in the application Note that in Figure 12-2, the image in the product summary area is not quite right. The image is cropped because it doesn’t fit in the area provided. Instead of resizing the application to fit the image, it is more reasonable to resize the image to fit the application. Scaling Images Resizing an image is also known as scaling. The quick and easy way to scale a GdkPixbuf is by using scale_simple. scale_simple takes a pixbuf, a new height, and a new width, and returns a new pixbuf with the given dimensions. ■Caution scale_simple scales the buffer exactly as it is told. It does not respect the aspect ratio of the original buffer. Make sure that the new dimensions you choose do not distort the buffer beyond your accept- able limits. scale_simple also requires one more argument, which tells GDK how to create the new image. Each of the following methods tells the pixbuf to scale the new image in a different manner, using a different algorithm. The faster the algorithm, the lower the quality of the scaled image. 6137ch12.qxd 3/14/06 2:29 PM Page 262 CHAPTER 12 ■ ADDING IMAGES 263 • Gdk::INTERP_NEAREST: This is the fastest way to scale an image, but the quality of the new image will likely be unacceptable, especially when making the image smaller. • Gdk::INTERP_HYPER: This produces the best-quality image, but may be too slow for some applications or for large images. • Gdk::INTERP_TILES: This method is probably best when you are not certain if the buffer is being scaled up or being scaled down. It resembles Gdk::INTERP_NEAREST when scaling up and Gdk::INTERP_BILINEAR when scaling down. • Gdk::INTERP_BILINEAR: This offers the best balance of quality and speed. In Listing 12-3, the product image for the product summary area is scaled to fit in the 100 × 100 pixel area set aside for the image. Listing 12-3. Scaling a GdkPixbuf <?php class Crisscott_Tools_ProductSummary extends GtkTable { // public function displaySummary(Crisscott_Product $product) { // // Remove the current product image. $this->productImage->remove($this->productImage->get_child()); // Try to add the product image. try { // Create a pixbuf. $pixbuf = GdkPixbuf::new_from_file($product->imagePath); // Scale the image. $pixbuf = $pixbuf->scale_simple(80, 100, Gdk::INTERP_BILINEAR); // Create an image from the pixbuf. $this->productImage->add(GtkImage::new_from_pixbuf($pixbuf)); // Show the image. $this->productImage->show_all(); } catch (Exception $e) { // Just fail silently. } } // } ?> Figure 12-3 shows the product summary area with the scaled image. 6137ch12.qxd 3/14/06 2:29 PM Page 263 CHAPTER 12 ■ ADDING IMAGES264 ■Tip Another method for scaling an image is named scale. scale is a very powerful method for manipu- lating images. Like scale_simple, it scales an image, but it also can take a portion of the new image and paste it onto an existing image. This method allows for some rather creative image manipulations, but is a little too complicated for use in most applications. For more details about using scale, consult the GdkPixbuf documentation at http://gtk.org. Setting Transparency Images can not only define visible pixels, but they also can define pixels that cannot be seen. These pixels are transparent. Transparent pixels allow the user to see through parts of an image. Transparent pixels are useful in cases where an image is a unique shape and you do not want to have a solid-colored background. For example, let’s say that the products can be rated from zero to five stars based on how well they sell. In order to make the application look clean and professional, the star icons depicting the rating should appear in the application without a background. The actual data that defines an image always defines a rectangular region. To show only the star shape, you can make some of the pixels in the rectangular region transparent and leave the pixels that represent the star as opaque. Most graphic editors, like The GIMP and Photoshop, allow you to create an image with transparent pixels built in. GdkPixbuf will respect transparent pixels that are built into an image file. However, it is sometime necessary to work with images that have been created without transparency. This doesn’t present too much of a problem, because you can add transparency to any GdkPixbuf that doesn’t have transparency already. You do this by creating an alpha channel for the GdkPixbuf. An alpha channel defines a particular color in an image to make transparent. The following line makes all white pixels in an image transparent: $newPixbuf = $pixbuf->add_alpha_channel(true, 255, 255, 255); The first argument to add_alpha_channel is a Boolean that tells the pixbuf to make the color transparent. The next three arguments define the color to make transparent. The color values here are 8-bit values for red, green, and blue (as opposed to the 16-bit values used by GdkColor). Now when the image shown, all white pixels will be transparent, and the color of the widget behind the image (usually a GtkButton or GtkWindow) will show through. Figure 12-3. A scaled product image 6137ch12.qxd 3/14/06 2:29 PM Page 264 CHAPTER 12 ■ ADDING IMAGES 265 Figure 12-4. A GtkTextView with pieces missing Animations Static images are not the only type of images that you can use with PHP-GTK. You can also load animations. An animation is a series of static images where the images are displayed one after another. An animation is useful to draw attention to an image. Something moving on the screen will be much more eye-catching than a static image. An animation can also be used as a sort of progress indicator. While work is being performed, you can display an animation. When the work is done, the animation can be replaced with a static image again. Working with animations is just like working with static images. In fact, an animation (most likely in .gif format) can even be loaded with GtkImage::new_from_file. When an animation is loaded into a GtkImage, it creates a GdkPixbufAnimation instead of a regular GdkPixbuf. A GtkImage that contains an animation can be added to a container just like any other widget. Widget Shaping You can use images for more than just adding pictures to an application. Using images, you can define shapes that you can then apply to windows and other widgets. An image can be used to turn a normal rectangular button into a symbol such as a plus sign, a star, or any other shape. Setting a widget’s shape is like trimming the widget using a stencil. The stencil defines which parts should be left and which parts should be removed. After the stencil is applied, all that is left of the widget are the parts the stencil did not say to trim. For example, Figure 12-4 shows a GtkTextView that has been modified to remove some parts from the middle. Notice how only the display of the widget is affected, not the actual shape of the widget. The text still flows as if the GtkTextView were square. ■Caution Users often associate particular shapes with specific actions. For instance, they often expect buttons and entries to be rectangular. Make sure that your modifications will have a positive impact on the usability of the application before straying from the customary shapes and sizes. 6137ch12.qxd 3/14/06 2:29 PM Page 265 CHAPTER 12 ■ ADDING IMAGES266 To shape a widget, you use a pixel map (pixmap) in combination with a bitmap. GdkPixmap is another format for storing image data in memory. The difference between a pixmap and a pixbuf is that a pixmap can be drawn onto by other GDK objects. A GdkPixmap is basically a way to map colors to a given pixel. The number of bits used to represent each color in the pixmap is called the depth. The greater the depth, the more colors a pixmap contains. One of the values that can be represented in a pixmap is transparency. Transparent pixels are basically pixels that do not exist. GdkBitmap, also known as a bitmask, is pixmap that has a depth of 1. In a bitmap, each bit does not represent a color, but rather indicates an on or off state. Pixels that are off are transparent. When a bitmap is laid over a GtkWindow, the bits that are off will not allow the window to show through. This is how a widget is shaped. The window in Figure 12-4 was created from the code in Listing 12-4. Listing 12-4. Changing the Shape of a GtkWindow <?php // Create a window. $window = new GtkWindow(); // Set up the window to exit cleanly. $window->connect_simple('destroy', array('Gtk', 'main_quit')); // Create a pixbuf from an image file. $pb = GdkPixbuf::new_from_file('Crisscott/images/inverse.png'); // Get the objects that will shape the widget. list($pixmap, $mask) = $pb->render_pixmap_and_mask(); // Create a GtkTextView and add some text. $text = new GtkTextView(); $text->get_buffer()->set_text('This is a test. There is a whole ' . 'in the middle of this text view widget.'); // Wrap the text. $text->set_wrap_mode(Gtk::WRAP_WORD); // Change the shape of the text view. $text->shape_combine_mask($mask, 0, 0); // Add the text view to the window. $window->add($text); // Show the window and image. $window->show_all(); // Start the main loop. Gtk::main(); ?> The first step in creating the “see-through” text view is to create a regular GtkWindow. Next, a pixbuf is created from an image file. After the pixbuf is created, it is used to generate two objects, one of which will be used as the stencil for shaping the window. The GdkPixbuf 6137ch12.qxd 3/14/06 2:29 PM Page 266 CHAPTER 12 ■ ADDING IMAGES 267 method render_pixmap_and_mask takes no arguments and returns an array containing a GdkPixmap and a GdkBitmap. The GdkBitmap is then passed to the window’s shape_combine_mask method. This method applies the mask to the GtkTextView, starting from the offset given by the last two arguments. In this case, the mask is not offset because both the x offset (second argument) and y offset (last argument) are 0. The rest of the example is pretty standard. The text view is added to the window, the window is shown, and the main loop is started. Summary Images are an essential for almost all applications. Simply displaying an image is rather easy. Once created, a GtkImage can be added to any container. All of the methods for GtkImage are either constructors for creating the image from different sources or methods for setting the contents of a previously created image. To work with the contents of an image, you must edit a pixel buffer, or pixbuf. GdkPixbuf stores an image and allows the image to be manipulated. A pixbuf can be scaled to a different size or turned into a pixel map (pixmap) and bitmask. You can use a GdkBitmap to give widgets a custom shape. This way, the use of images in an application not only makes the application more visually appealing, but can also shape the application itself. Chapter 13 looks at what it takes to allow users to drag objects in an application and move them to another part of the application. This is known as drag-and-drop. You will learn not only how to make an item draggable, but also how to make a widget accept or reject items for dropping. 6137ch12.qxd 3/14/06 2:29 PM Page 267 [...]... expand and fill properties $expandFill = Gtk::EXPAND|Gtk::FILL; // // Create a frame to hold the product summary tool $productSummary = new GtkFrame('PRODUCT SUMMARY'); $productSummary->set_size_request(-1, 150); // Add the product summary tool require_once 'Crisscott/Tools/ProductSummary.php'; $this->productSummary = Crisscott_Tools_ProductSummary::singleton(); $productSummary->add($this->productSummary);... to get the appropriate data $eb->connect('drag-data-get', array($this, 'getSummaryDragData'), $this->productSummary) // } public function getSummaryDragData($widget, $context, $selection, $info, $time, $summary) { // Set the product id as the selection's data value $selection->set_text($summary->product->productId); } // } ?> In Listing 13-4, the set_text method is used to set the data property of... They do not allow the button to close the dialog and emit the response signal with a response ID 287 6137ch14.qxd 288 3/14/06 2:33 PM Page 288 CHAPTER 14 ■ USING SELECTORS & DIALOGS While the application could create the needed signal handlers, there is a better way to add items to the action area The proper way to add a button to a GtkDialog is by using one of the following: • add_button: The add_button... } ?> In Listing 13-4, the set_text method is used to set the data property of the GtkSelectionData object to the product ID of the ProductSummary tool’s current product When the GtkSelectionData object is passed on to the drag destination, the product ID can be retrieved from the data property of the selection object Setting Drag Source Icons When data is dragged from one place to another, the cursor... the request has been satisfied Prompts that pose a specific question are known as dialogs, while those that ask the user to make a selection are known as selectors For example, the prompt to confirm the closure of a file without first saving it is known as a dialog, while the prompt to choose a specific filename is a selector PHP-GTK 2 offers several widgets that make the process of creating and displaying... array(array('text/plain', 0, 0)), Gdk::ACTION_COPY); // Create a signal handler to get the appropriate data $eb->connect('drag-data-get', array($this, 'getSummaryDragData'), $this->productSummary); // Add the product summary to the event box $eb->add($this->productSummary); // } // } ?> One of the key things to notice about Listing 13-3 is that the ProductSummary tool itself is not made a drag source This is because no-window... source is a Crisscott product, the drag icon could be set to a small version of the Crisscott logo This lets the users know that they are moving product data and not just an image or chunk of text Setting a custom icon is a simple matter of passing a GdkPixbuf object to a widget’s drag_source_set_icon_pixbuf Listing 13-5 shows a simple example 277 6137ch13.qxd 2 78 3/14/06 2:30 PM Page 2 78 CHAPTER 13 ■ DRAG-AND-DROP... 3/14/06 2:30 PM Page 280 6137ch14.qxd 3/14/06 2:33 PM CHAPTER Page 281 14 ■■■ Using Selectors & Dialogs U ser decisions are ultimately responsible for determining the course of an application’s actions For instance, a user is often prompted to confirm a pending action, such as closing a file without saving, or choosing a particular value such as a filename or color Normally, such prompts do not need... 17); // Check the mime type to make sure the file is an image if (strpos(mime_content_type($path), 'image') === false) { return false; } // Set the current product's image path $this->product->imagePath = $path; // Reset the product $this->resetProduct(); } // } ?> ■ Caution File URIs are seldom implemented correctly The correct format is file://hostname/path/ to/file Because of the many different... widgets, provide a few hints as to what the contents should be, and wait for the pop-up to return information regarding the user’s choice This chapter examines what is required to set up and communicate with the many types of dialogs and selectors available in PHP-GTK 2 Dialogs GtkDialog is a widget designed to prompt the user to answer a question using a top-level window that displays a message, providing . displaySummary(Crisscott_Product $product) { // Set the product. $this->product = $product; // Set the attribute labels to the values of the product. $this->productName->set_text($product->name); $this->productType->set_text($product->type); //. function resetProduct() { // Make sure that there is a product. if (!isset($this->product)) { require_once 'Crisscott/Product.php'; $this->product = new Crisscott_Product(); } //. displaySummary(Crisscott_Product $product) { // // Remove the current product image. $this->productImage->remove($this->productImage->get_child()); // Try to add the product image. try