Blame platform-demos/gl/image-viewer.py.page

Packit 1470ea
Packit 1470ea
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.py" xml:lang="gl">
Packit 1470ea
Packit 1470ea
  <info>
Packit 1470ea
    <title type="text">Image viewer (Python)</title>
Packit 1470ea
    <link type="guide" xref="py#examples"/>
Packit 1470ea
Packit 1470ea
    <desc>Algo máis que un aplicativo sinxelo «Hola mundo» - escribir un visor de imaxes en GTK.</desc>
Packit 1470ea
Packit 1470ea
    <revision pkgversion="0.1" version="0.1" date="2011-03-19" status="review"/>
Packit 1470ea
    <credit type="author">
Packit 1470ea
      <name>Jonh Wendell</name>
Packit 1470ea
      <email its:translate="no">jwendell@gnome.org</email>
Packit 1470ea
    </credit>
Packit 1470ea
    <credit type="author">
Packit 1470ea
      <name>Johannes Schmid</name>
Packit 1470ea
      <email its:translate="no">jhs@gnome.org</email>
Packit 1470ea
    </credit>
Packit 1470ea
    <credit type="editor">
Packit 1470ea
      <name>Marta Maria Casetti</name>
Packit 1470ea
      <email its:translate="no">mmcasetti@gmail.com</email>
Packit 1470ea
      <years>2013</years>
Packit 1470ea
    </credit>
Packit 1470ea
  
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Fran Dieguez</mal:name>
Packit 1470ea
      <mal:email>frandieguez@gnome.org</mal:email>
Packit 1470ea
      <mal:years>2012-2013.</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  </info>
Packit 1470ea
Packit 1470ea
<title>Image viewer</title>
Packit 1470ea
Packit 1470ea
<synopsis>
Packit 1470ea
  

Neste titorial, imos escribir un aplicativo GTK moi sinxelo que carga e mostra un ficheiro de imaxe. Vostede aprenderá a:

Packit 1470ea
  <list>
Packit 1470ea
    <item>

Escribir unha interface de usuario básica en Python

</item>
Packit 1470ea
    <item>

Xestionar eventos conectando sinais a xestores de sinais

</item>
Packit 1470ea
    <item>

Dispoñer interfaces de usuario GTK usando contedores

</item>
Packit 1470ea
    <item>

Cargar e mostrar ficheiros de imaxe

</item>
Packit 1470ea
  </list>
Packit 1470ea
  

You'll need the following to be able to follow this tutorial:

Packit 1470ea
  <list>
Packit 1470ea
    <item>

An installed copy of the <link xref="getting-ready">Anjuta IDE</link>

</item>
Packit 1470ea
    <item>

Basic knowledge of the python programming language

</item>
Packit 1470ea
  </list>
Packit 1470ea
</synopsis>
Packit 1470ea
Packit 1470ea
<media type="image" mime="image/png" src="media/image-viewer.png"/>
Packit 1470ea
Packit 1470ea
<section id="anjuta">
Packit 1470ea
  <title>Cree un proxecto de Anjuta</title>
Packit 1470ea
  

Antes de comezar a programar, deberá configurar un proxecto novo en Anjuta. Isto creará todos os ficheiros que precise para construír e executar o código máis adiante. Tamén é útil para manter todo ordenado.

Packit 1470ea
  <steps>
Packit 1470ea
    <item>
Packit 1470ea
    

Inicie Anjuta e prema <guiseq><gui>Ficheiro</gui><gui>Novo</gui><gui>Proxecto</gui></guiseq> para abrir o asistente de proxectos.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Choose <gui>PyGTK (automake)</gui> from the <gui>Python</gui> tab, click <gui>Continue</gui>, and fill out your details on the next few pages. Use <file>image-viewer</file> as project name and directory.

Packit 1470ea
   	</item>
Packit 1470ea
   	<item>
Packit 1470ea
   	

Be sure to disable <gui>Use GtkBuilder for user interface</gui> as we will build the

Packit 1470ea
       user interface manually in this example. For an example of using the interface designer,
Packit 1470ea
   	check the <link xref="guitar-tuner.py">Guitar-Tuner demo</link>.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

Prema <gui>Aplicar</gui> e crearase o proxecto. Abra <file>src/image_viewer.py</file> desde as lapelas <gui>Proxecto</gui> ou <gui>Ficheiro</gui>. Contén un exemplo de código moi básico:

Packit 1470ea
    </item>
Packit 1470ea
  </steps>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="first">
Packit 1470ea
  <title>Un primeiro aplicativo en GTK</title>
Packit 1470ea
  

Vexamos como é o máis básico dun aplicativo Gtk en Python:

Packit 1470ea
  
Packit 1470ea
from gi.repository import Gtk, GdkPixbuf, Gdk
Packit 1470ea
import os, sys
Packit 1470ea
Packit 1470ea
class GUI:
Packit 1470ea
	def __init__(self):
Packit 1470ea
		window = Gtk.Window()
Packit 1470ea
		window.set_title ("Hello World")
Packit 1470ea
		window.connect_after('destroy', self.destroy)
Packit 1470ea
Packit 1470ea
		window.show_all()
Packit 1470ea
Packit 1470ea
	def destroy(window, self):
Packit 1470ea
		Gtk.main_quit()
Packit 1470ea
Packit 1470ea
def main():
Packit 1470ea
	app = GUI()
Packit 1470ea
	Gtk.main()
Packit 1470ea
Packit 1470ea
if __name__ == "__main__":
Packit 1470ea
    sys.exit(main())
Packit 1470ea
]]>
Packit 1470ea
  
Packit 1470ea
  

Botemos unha ollada ao que está pasando:

Packit 1470ea
  <list>
Packit 1470ea
    <item>
Packit 1470ea
    

The first line imports the Gtk namespace (that is, it includes the Gtk library). The libraries are provided by GObject Introspection (gi), which provides language bindings for many GNOME libraries.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

In the __init__ method of the GUI class creates an

Packit 1470ea
    (empty) Gtk.Window, sets its title and then connects a signal to quit the application
Packit 1470ea
    once the window is closed. That's pretty simple overall, more on signals later.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

A continuación, destroy está definido só para saír do aplicativo. É chamado pola sinal destroy conectada enriba.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

O resto do ficheiro inicializa Gtk e mostra o GUI.

Packit 1470ea
    </item>
Packit 1470ea
  </list>
Packit 1470ea
Packit 1470ea
  

This code is ready to run, so try it using <guiseq><gui>Run</gui><gui>Execute</gui></guiseq>.

Packit 1470ea
   It should show you an empty window.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="signals">
Packit 1470ea
  <title>Sinais</title>
Packit 1470ea
  

Signals are one of the key concepts in Gtk programming. Whenever something happens to an object, it emits a signal; for example, when a button is clicked it gives off the clicked signal. If you want your program to do something when that event occurs, you must connect a function (a "signal handler") to that signal. Here's an example:

Packit 1470ea
  
Packit 1470ea
def button_clicked () :
Packit 1470ea
  print "you clicked me!"
Packit 1470ea
Packit 1470ea
b = new Gtk.Button ("Click me")
Packit 1470ea
b.connect_after ('clicked', button_clicked)]]>
Packit 1470ea
  

The last two lines create a Gtk.Button called b and connect its clicked signal to the button_clicked function, which is defined above. Every time the button is clicked, the code in the button_clicked function will be executed. It just prints a message here.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="containers">
Packit 1470ea
  <title>Contedores: deseñar a interface de usuario</title>
Packit 1470ea
  

Widgets (controls, such as buttons and labels) can be arranged in the window by making use of containers. You can organize the layout by mixing different types of containers, like boxes and grids.

Packit 1470ea
  

A Gtk.Window is itself a type of container, but you can only put one widget directly into it. We would like to have two widgets, an image and a button, so we must put a "higher-capacity" container inside the window to hold the other widgets. A number of <link href="http://library.gnome.org/devel/gtk/stable/GtkContainer.html">container types</link> are available, but we will use a Gtk.Box here. A Gtk.Box can hold several widgets, organized horizontally or vertically. You can do more complicated layouts by putting several boxes inside another box and so on.

Packit 1470ea
  <note>
Packit 1470ea
  

There is a graphical user interface designer called <app>Glade</app> integrated in <app>Anjuta</app> which makes UI design really easy. For this simple example, however, we will code everything manually.

Packit 1470ea
  </note>
Packit 1470ea
  

Let's add the box and widgets to the window. Insert the following code into the __init__ method, immediately after the window.connect_after line:

Packit 1470ea
Packit 1470ea
box = Gtk.Box()
Packit 1470ea
box.set_spacing (5)
Packit 1470ea
box.set_orientation (Gtk.Orientation.VERTICAL)
Packit 1470ea
window.add (box)
Packit 1470ea
]]>
Packit 1470ea
Packit 1470ea
  

The first line creates a Gtk.Box called box and the following lines set two of its properties: the orientation is set to vertical (so the widgets are arranged in a column), and the spacing between the widgets is set to 5 pixels. The next line then adds the newly-created Gtk.Box to the window.

Packit 1470ea
  

So far the window only contains an empty Gtk.Box, and if you run the program now you will see no changes at all (the Gtk.Box is a transparent container, so you can't see that it's there).

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="packing">
Packit 1470ea
  <title>Empaquetado: Engadir widgets ao contedor</title>
Packit 1470ea
  

To add some widgets to the Gtk.Box, insert the following code directly below the window.add (box) line:

Packit 1470ea
  
Packit 1470ea
self.image = Gtk.Image()
Packit 1470ea
box.pack_start (self.image, False, False, 0)]]>
Packit 1470ea
  

The first line creates a new Gtk.Image called image, which will be used to display an image file.

Packit 1470ea
As we need that later on in the signal handler, we will define it as a class-wide variable. You need to add image = 0 to the beginning of the GUI class. Then, the image widget is added (packed) into the box container using GtkBox's <link href="http://library.gnome.org/devel/gtk/stable/GtkBox.html#gtk-box-pack-start">pack_start</link> method.

Packit 1470ea
  

pack_start takes 4 arguments: the widget that is to be added to the GtkBox (child); whether the Gtk.Box should grow larger when the new widget is added (expand); whether the new widget should take up all of the extra space created if the Gtk.Box gets bigger (fill); and how much space there should be, in pixels, between the widget and its neighbors inside the Gtk.Box (padding).

Packit 1470ea
  

Gtk containers (and widgets) dynamically expand to fill the available space, if you let them. You don't position widgets by giving them a precise x,y-coordinate location in the window; rather, they are positioned relative to one another. This makes handling window resizing much easier, and widgets should automatically take a sensible size in most situations.

Packit 1470ea
  

Also note how the widgets are organized in a hierarchy. Once packed in the Gtk.Box, the Gtk.Image is considered a child of the Gtk.Box. This allows you to treat all of the children of a widget as a group; for example, you could hide the Gtk.Box, which would also hide all of its children at the same time.

Packit 1470ea
  

Agora escriba estas dúas liñas, embaixo das dúas que acaba de engadir:

Packit 1470ea
  
Packit 1470ea
button = Gtk.Button ("Open a picture...")
Packit 1470ea
box.pack_start (button, False, False, 0)
Packit 1470ea
]]>
Packit 1470ea
  

These lines are similar to the first two, but this time they create a Gtk.Button and add it to box. Notice that we are setting the expand argument (the second one) to False here, whereas it was set to True for the Gtk.Image. This will cause the image to take up all available space and the button to take only the space it needs. When you maximize the window, the button size will remain the same, but the image size will increase, taking up all of the rest of the window.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="loading">
Packit 1470ea
  <title>Loading the image: Connecting to the button's clicked signal</title>
Packit 1470ea
  

When the user clicks on the <gui>Open Image...</gui> button, a dialog should appear so that the user can choose a picture. Once chosen, the picture should be loaded and shown in the image widget.

Packit 1470ea
  

The first step is to connect the clicked signal of the button to a signal handler function, which we call on_open_clicked. Put this code immediately after the button = Gtk.Button() line where the button was created:

Packit 1470ea
  
Packit 1470ea
button.connect_after('clicked', self.on_open_clicked)
Packit 1470ea
]]>
Packit 1470ea
  

This will connect the clicked signal to on_open_clicked method that we will define

Packit 1470ea
below.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="loading2">
Packit 1470ea
  <title>Loading the image: Writing the signal's callback</title>
Packit 1470ea
  

Now we can create the on_open_clicked method. Insert the following into the GUI class code block, after the __init__ method:

Packit 1470ea
    
Packit 1470ea
def on_open_clicked (self, button):
Packit 1470ea
	dialog = Gtk.FileChooserDialog ("Open Image", button.get_toplevel(), Gtk.FileChooserAction.OPEN);
Packit 1470ea
	dialog.add_button (Gtk.STOCK_CANCEL, 0)
Packit 1470ea
	dialog.add_button (Gtk.STOCK_OK, 1)
Packit 1470ea
	dialog.set_default_response(1)
Packit 1470ea
Packit 1470ea
	filefilter = Gtk.FileFilter ()
Packit 1470ea
	filefilter.add_pixbuf_formats ()
Packit 1470ea
	dialog.set_filter(filefilter)
Packit 1470ea
Packit 1470ea
	if dialog.run() == 1:
Packit 1470ea
		self.image.set_from_file(dialog.get_filename())
Packit 1470ea
Packit 1470ea
	dialog.destroy()]]>
Packit 1470ea
  

This is a bit more complicated than anything we've attempted so far, so let's break it down:

Packit 1470ea
  <list>
Packit 1470ea
    <item>
Packit 1470ea
      

The line beginning with dialog creates an <gui>Open</gui> dialog, which the user can use to choose files. We set three properties: the title of the dialog; the action (type) of the dialog (it's an "open" dialog, but we could have used SAVE if the intention was to save a file; and transient_for, which sets the parent window of the dialog.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

The next two lines add <gui>Cancel</gui> and <gui>Open</gui> buttons to the dialog. The second argument of the add_button method is the (integer) value that is returned when the button is pressed: 0 for <gui>Cancel</gui> and 1 for <gui>Open</gui>.

Packit 1470ea
    

Notice that we are using stock button names from Gtk, instead of manually typing "Cancel" or "Open". The advantage of using stock names is that the button labels will already be translated into the user's language.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

set_default_response determines the button that will be activated if the user double-clicks a file or presses <key>Enter</key>. In our case, we are using the <gui>Open</gui> button as default (which has the value 1).

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

The next three lines restrict the <gui>Open</gui> dialog to only display files which can be opened by Gtk.Image. A filter object is created first; we then add all kinds of files supported by Gdk.Pixbuf (which includes most image formats like PNG and JPEG) to the filter. Finally, we set this filter to be the <gui>Open</gui> dialog's filter.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

dialog.run displays the <gui>Open</gui> dialog. The dialog will wait for the user to choose an image; when they do, dialog.run will return the value <output>1</output> (it would return <output>0</output> if the user clicked <gui>Cancel</gui>). The if statement tests for this.

Packit 1470ea
    </item>
Packit 1470ea
    <item>

Assuming that the user did click <gui>Open</gui>, the next line sets the file property of the Gtk.Image to the filename of the image selected by the user. The Gtk.Image will then load and display the chosen image.

Packit 1470ea
    </item>
Packit 1470ea
    <item>
Packit 1470ea
    

In the final line of this method, we destroy the <gui>Open</gui> dialog because we don't need it any more.

Packit 1470ea
    </item>
Packit 1470ea
  </list>
Packit 1470ea
Packit 1470ea
  </section>
Packit 1470ea
Packit 1470ea
<section id="run">
Packit 1470ea
  <title>Executar o aplicativo</title>
Packit 1470ea
  

All of the code you need should now be in place, so try running the code. That should be it; a fully-functioning image viewer (and a whistlestop tour of Python and Gtk) in not much time at all!

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="impl">
Packit 1470ea
 <title>Implementación de referencia</title>
Packit 1470ea
 

If you run into problems with the tutorial, compare your code with this <link href="image-viewer/image-viewer.py">reference code</link>.

Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
<section id="next">
Packit 1470ea
  <title>Seguintes pasos</title>
Packit 1470ea
  

Aquí hai algunhas ideas sobre como pode estender esta sinxela demostración:

Packit 1470ea
  <list>
Packit 1470ea
   <item>
Packit 1470ea
   

Have the user select a directory rather than a file, and provide controls to cycle through all of the images in a directory.

Packit 1470ea
   </item>
Packit 1470ea
   <item>
Packit 1470ea
   

Aplicar filtros aleatorios e efectos á imaxe cando se carga e permitir ao usuario gardar a imaxe modificada.

Packit 1470ea
   

<link href="http://www.gegl.org/api.html">GEGL</link> fornece capacidades moi potentes de manipulación de imaxes.

Packit 1470ea
   </item>
Packit 1470ea
   <item>
Packit 1470ea
   

Permitir ao usuario cargar imaxes desde recursos de rede compartidos, escáneres e outras fontes máis complicadas.

Packit 1470ea
   

You can use <link href="http://library.gnome.org/devel/gio/unstable/">GIO</link> to handle network file transfers and the like, and <link href="http://library.gnome.org/devel/gnome-scan/unstable/">GNOME Scan</link> to handle scanning.

Packit 1470ea
   </item>
Packit 1470ea
  </list>
Packit 1470ea
</section>
Packit 1470ea
Packit 1470ea
</page>