Ejemplos de código
En esta sección se exponen extractos de código de distinta complejidad a modo de ejemplo y aplicaciones desarrolladas con Genie.
Siempre viene bien ver cómo lo hacen otros.
Tabla de Contenidos
Stats Calc
Calculadora estadística. Se trata de un proyecto en una fase inicial de desarrollo, en el que el autor de esta Wiki pone en práctica algunos de los contenidos aquí expuestos, y en particular la interfaz gráfica Gtk y las colecciones, entre otros. Ocasionalmente también se utilizan otros recursos que (todavía) no han sido tratados en Genie Doc.
Código disponible en el repositorio de GitHub StatsCalc. También disponible en paquete deb listo para instalar.
Capturas de pantalla:
AgenDie
AgenDie es una aplicación que recrea una agenda de contactos. Como tal, dispone de las funciones básicas de una libreta de direcciones o directorio para organizar contactos: añadir, eliminar, editar y buscar contactos.
Se trata de un proyecto en una fase inicial de desarrollo, en el que el autor de esta Wiki pone en práctica algunos de los contenidos aquí expuestos, y en particular la interfaz gráfica Gtk, la base de datos SQLite y las listas, entre otros. Ocasionalmente también se utilizan otros recursos que (todavía) no han sido tratados en Genie Doc.
Desde la web del proyecto, publicado en Launchpad, se puede obtener el código y descargar un paquete deb para instalar. También publicado en un repositorio de GitHub.
Desde allí se pueden seguir los progresos de la aplicación y aportar sugerencias e ideas para mejorarlo.
Game Classic: Number Guessing
Código tomado de Projects Genie y traducido para esta Wiki. Juego para adivinar un número.
- NumberGuessing.gs
class NumberGuessing prop min : int prop max : int construct ( m : int, n : int) self.min = m self.max = n def start() try_count : int = 0 number : int = Random.int_range (min, max) stdout.printf ("Bienvenido a ¡Adivina un número!\n\n") stdout.printf ("Yo estoy pensando un número entre %d y %d\n", min, max) stdout.printf ("que tienes que adivinar. Pero no te preocupes, te\n") stdout.printf ("daré algunas pistas.\n\n") while true stdout.printf ("Intento #%d\n", ++try_count) stdout.printf ("Por favor, introduce un número entre %d y %d: ", min, max) input : int = int.parse (stdin.read_line ()) if number is input stdout.printf ("¡Felicidades! Lo has adivinado.\n") break else stdout.printf ("Incorrecto. El número que buscas es %s que %d.\n", number > input ? "mayor" : "menor", input) init var game = new NumberGuessing(1, 100) game.start()
A for loop and a password routine
Código enviado a Stack Overflow en respuesta a una consulta sobre un código de verificación de contraseña (solución sin necesidad de la librería libgee).
- password.gs
init users: array of string = {"Fred","John","Steve","Ann","Mary"} passwords: array of string = {"access","dog","12345","kids","qwerty"} print "Enter user name" usrname:string = stdin.read_line() print "Enter password" pwd:string = stdin.read_line() error:int = 0 cont:int = 0 for var user in users if (user!=usrname) error++ if error == (users.length) print "No reconocido. Acceso denegado." if (user==usrname) position:int = cont if pwd == passwords[position] print "OK: Acceso Concedido." else print "Password incorrecta." cont++
Simple Text Viewer
Como su nombre indica, un sencillo visor de texto que ha sido programado con Genie y que utiliza la interfaz gráfica Gtk. Tomado del foro Vala and Genie programming y corregido para esta Wiki.
- SimpleTextViewer.gs
// compilar con valac --pkg gtk+-3.0 nombre_archivo.gs uses Gtk init Gtk.init (ref args) var test = new TextFileViewer () test.show_all () Gtk.main (); class TextFileViewer : Window text_view : TextView init title = "Simple Text Viewer" default_height = 350 default_width = 500 window_position = WindowPosition.CENTER destroy += Gtk.main_quit var toolbar = new Toolbar () var open_button = new ToolButton.from_stock (STOCK_OPEN) var quit_button = new ToolButton.from_stock (STOCK_QUIT) toolbar.add (open_button) toolbar.add (quit_button) open_button.clicked += on_open_clicked quit_button.clicked += Gtk.main_quit this.text_view = new TextView () this.text_view.editable = false this.text_view.cursor_visible = true var scroll = new ScrolledWindow (null, null) scroll.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC) scroll.add (this.text_view) var vbox = new VBox (false, 0) vbox.pack_start (toolbar, false, true, 0) vbox.pack_start (scroll, true, true, 0) add (vbox) def private on_open_clicked () var file_chooser = new FileChooserDialog ("Open File", this, FileChooserAction.OPEN, STOCK_CANCEL, ResponseType.CANCEL, STOCK_OPEN, ResponseType.ACCEPT, null) if (file_chooser.run () == ResponseType.ACCEPT) open_file (file_chooser.get_filename ()) file_chooser.destroy () def private open_file (filename : string) try text : string len : ulong FileUtils.get_contents (filename, out text, out len) leni:int = 0 leni = (int) len this.text_view.buffer.set_text (text, leni) except e:OptionError stdout.printf ("%s\n", e.message)
Writing a gedit Plugin with Genie
Tutorial sobre cómo programar con Genie un plugin para Gedit.
TreeView List Example
Código tomado de srackham | blog. La interfaz de usuario se construyó utilizando Glade.
- treeview-list.gs
/* treeview-list.gs - Genie TreeView list example Build with: valac --pkg gtk+-2.0 --pkg posix treeview-list.gs */ init Gtk.init(ref args) var app = new App () app.start () Gtk.main () class App: Object window: Gtk.Window treeview: Gtk.TreeView liststore: Gtk.ListStore msg_label: Gtk.Label struct Person id: int name: string city: string country: string def to_string (): string return @"$(id), $(name), $(city), $(country)" data: array of Person = { Person() {id=1, name="Joe Bloggs", city="London", country="England"}, Person() {id=2, name="Bill Smith", city="Auckland", country="New Zealand"}, Person() {id=3, name="Joan Miller", city="Boston", country="USA"} } init var builder = new Gtk.Builder() try builder.add_from_file("treeview-list.ui") except e:Error stderr.printf(@"$(e.message)\n") Posix.exit(1) builder.connect_signals(this) this.window = builder.get_object("window") as Gtk.Window this.msg_label = builder.get_object("msg-label") as Gtk.Label this.treeview = builder.get_object ("treeview") as Gtk.TreeView // Load list data. this.liststore = builder.get_object ("liststore") as Gtk.ListStore this.liststore.clear () for p: Person in this.data iter: Gtk.TreeIter this.liststore.append (out iter) this.liststore.set (iter, 0, p.id, 1, p.name, 2, p.city, 3, p.country) // Monitor list double-clicks. this.treeview.row_activated.connect (on_row_activated) // Monitor list selection changes. this.treeview.get_selection().changed.connect (on_selection) this.window.destroy.connect (Gtk.main_quit) def start () this.window.show_all (); def static get_selection (model: Gtk.TreeModel, iter: Gtk.TreeIter): Person var p = Person() model.get (iter, 0, out p.id, 1, out p.name, 2, out p.city, 3, out p.country) return p /* List item double-click handler. */ def on_row_activated (treeview: Gtk.TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn) iter: Gtk.TreeIter if treeview.model.get_iter (out iter, path) p: Person = get_selection (treeview.model, iter) this.msg_label.label = @"Double-clicked: $(p)" /* List item selection handler. */ def on_selection (selection: Gtk.TreeSelection) model: Gtk.TreeModel iter: Gtk.TreeIter if selection.get_selected (out model, out iter) p: Person = get_selection (model, iter) this.msg_label.label = @"Selected: $(p)"
- treeview-list.ui
<?xml version="1.0"?> <interface> <requires lib="gtk+" version="2.16"/> <!-- interface-naming-policy project-wide --> <object class="GtkListStore" id="liststore"> <columns> <!-- column-name id --> <column type="gint"/> <!-- column-name name --> <column type="gchararray"/> <!-- column-name city --> <column type="gchararray"/> <!-- column-name country --> <column type="gchararray"/> </columns> </object> <object class="GtkWindow" id="window"> <property name="title" translatable="yes">TreeView List Example</property> <property name="window_position">center</property> <property name="default_width">440</property> <property name="default_height">250</property> <child> <object class="GtkVBox" id="vbox1"> <property name="visible">True</property> <child> <object class="GtkScrolledWindow" id="scrolledwindow1"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hscrollbar_policy">automatic</property> <property name="vscrollbar_policy">automatic</property> <child> <object class="GtkTreeView" id="treeview"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="model">liststore</property> <child> <object class="GtkTreeViewColumn" id="treeviewcolumn1"> <property name="title">Name</property> <child> <object class="GtkCellRendererText" id="cellrenderertext1"/> <attributes> <attribute name="text">1</attribute> </attributes> </child> </object> </child> <child> <object class="GtkTreeViewColumn" id="treeviewcolumn2"> <property name="title">City</property> <child> <object class="GtkCellRendererText" id="cellrenderertext2"/> <attributes> <attribute name="text">2</attribute> </attributes> </child> </object> </child> <child> <object class="GtkTreeViewColumn" id="treeviewcolumn3"> <property name="title">Country</property> <child> <object class="GtkCellRendererText" id="cellrenderertext3"/> <attributes> <attribute name="text">3</attribute> </attributes> </child> </object> </child> </object> </child> </object> <packing> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="msg-label"> <property name="visible">True</property> <property name="xalign">0</property> <attributes> <attribute name="weight" value="bold"/> <attribute name="foreground" value="#30af5549c84f"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="padding">2</property> <property name="position">1</property> </packing> </child> </object> </child> </object> </interface>
Tenis: Genie + SDL
Para ver el proceso de desarrollo y más detalles visita el apartado sobre SDL en esta Wiki. También desde allí puedes descargar el archivo compilado y los archivos de sonido necesarios.
- tenis.gs
// compila con valac --pkg sdl --pkg sdl-gfx -X -lSDL_gfx --pkg sdl-mixer -X -lSDL_mixer nombre_archivo.gs uses SDL uses SDLGraphics uses SDLMixer // sonido archivo1: SDL.RWops archivo2: SDL.RWops sonido1: SDLMixer.Chunk sonido2: SDLMixer.Chunk canal1: SDLMixer.Channel canal2: SDLMixer.Channel init titulo:string = "Genie SDL Demo" ancho:int16 = 640 alto:int16 = 480 bpp:int = 16 flags:uint32 = SurfaceFlag.FULLSCREEN | SurfaceFlag.DOUBLEBUF | SurfaceFlag.HWACCEL | SurfaceFlag.HWSURFACE | SurfaceFlag.ANYFORMAT screen: unowned SDL.Screen tenis:bool = false juego: SDL.Event intro:bool = false inicio: SDL.Event gameover:bool = true evento: SDL.Event pausa:bool = false saque: bool = true fin:bool = false var x = 100 var y = 240 var new_x = 0 var new_y = 0 var pos1 = 200 var pos2 = 200 var pos1_new = 0 var pos2_new = 0 mar1:int = 0 mar2:int = 0 marca1:string marca2: string SDL.init(SDL.InitFlag.VIDEO) SDL.WindowManager.set_caption (titulo, "") screen = SDL.Screen.set_video_mode (ancho, alto, bpp, flags) //oculta cursor SDL.Cursor.show(0) // sonidos SDLMixer.open(44100,SDL.AudioFormat.S16LSB,2,4096) archivo1 = new SDL.RWops.from_file ("/home/jcv/Programacion/Genie/SDL/Boing.ogg","rb") sonido1 = new SDLMixer.Chunk.WAV (archivo1,-1) archivo2 = new SDL.RWops.from_file ("/home/jcv/Programacion/Genie/SDL/error.ogg","rb") sonido2 = new SDLMixer.Chunk.WAV (archivo2,-1) while (!tenis) while (Event.poll (out juego)) == 1 // pantalla de inicio while (!intro) while (Event.poll (out inicio)) == 1 case inicio.type when SDL.EventType.QUIT intro = true tenis = true break when EventType.KEYDOWN case inicio.key.keysym.sym when KeySymbol.ESCAPE intro = true tenis = true break when KeySymbol.i intro = true gameover = false break Rectangle.fill_rgba(screen, 0, 0, ancho, alto, 0, 0, 0, 200) Text.rgba(screen, 260, 100, "JUEGO DE TENIS RETRO", 255, 255, 255, 200) Text.rgba(screen, 300, 180, "CONTROLES", 255, 255, 255, 200) Text.rgba(screen, 160, 200, "Inicio: I Salir : ESC Pausa: P", 255, 255, 255, 200) Text.rgba(screen, 160, 240, " Jugador 1 Jugador 2", 255, 255, 255, 200) Text.rgba(screen, 160, 260, "Subir: A Up", 255, 255, 255, 200) Text.rgba(screen, 160, 280, "Bajar: Z Down", 255, 255, 255, 200) Text.rgba(screen, 160, 300, "Sacar: Q", 255, 255, 255, 200) screen.flip() // pantalla de juego while (!gameover) while (Event.poll (out evento)) == 1 case evento.type when SDL.EventType.QUIT gameover = true intro = false break when EventType.KEYDOWN case evento.key.keysym.sym when KeySymbol.ESCAPE // reiniciar variables x = 100 y = 240 new_x = 0 new_y = 0 pos1 = 200 pos2 = 200 pos1_new = 0 pos2_new = 0 mar1 = 0 mar2 = 0 fin = false gameover = true saque = true intro = false break when KeySymbol.q if saque == true new_x = 2 var saque_y = Random.int_range (1, 3) if saque_y == 1 new_y = -2 else new_y = 2 canal1.play(sonido1,0) // sonido de saque saque = false when KeySymbol.p //pausa if pausa == false pausa = true else if pausa == true pausa = false break when KeySymbol.a pos1_new = -1 break when KeySymbol.z pos1_new = +1 break when KeySymbol.UP pos2_new = -1 break when KeySymbol.DOWN pos2_new = +1 break when EventType.KEYUP case evento.key.keysym.sym when KeySymbol.a pos1_new = 0 break case evento.key.keysym.sym when KeySymbol.z pos1_new = 0 break case evento.key.keysym.sym when KeySymbol.UP pos2_new = 0 break case evento.key.keysym.sym when KeySymbol.DOWN pos2_new = 0 break // pausa while (pausa == true) SDL.Event.wait (out evento) Text.rgba(screen, 260, 240, "JUEGO EN PAUSA (P)", 255, 255, 255, 200) screen.flip() if evento.type == EventType.KEYDOWN if evento.key.keysym.sym == KeySymbol.p pausa = false break // actualiza la posición de los jugadores pos1 += pos1_new pos2 += pos2_new // evita que los jugadores se salgan de la pantalla if pos1 < 0 do pos1 = -1 if pos1 > 400 do pos1 = 401 if pos2 < 0 do pos2 = -1 if pos2 > 400 do pos2 = 401 // rebota en las paredes if x > ancho or x < 0 canal2.play(sonido2,0) if x < 0 mar2 += 1 if x > ancho mar1 += 1 new_x = -new_x if y > alto or y < 0 new_y = -new_y // rebota en los rectángulos de los jugadores // jugador 1 if (x > 60 and x < 65) and (y >= pos1 and y <= pos1+80) if y == pos1 or y == pos1+80 new_y = -new_y else new_x = -new_x canal1.play(sonido1,0) // jugador 2 if (x > 575 and x < 580) and (y >= pos2 and y <= pos2+80) if y == pos2 or y == pos2+80 new_y = -new_y else new_x = -new_x canal1.play(sonido1,0) x = x + new_x y = y + new_y // fondo y linea central Line.rgba(screen, 320, 40, 320, 440, 255, 255, 255, 128) Rectangle.fill_rgba(screen, 0, 0, ancho, alto, 0, 128, 255, 128) // jugadores Rectangle.fill_rgba(screen, 60, pos1, 65, pos1+80, 255, 255, 255, 200) Rectangle.fill_rgba(screen, 575, pos2, 580, pos2+80, 255, 255, 255, 200) // pelota Circle.fill_rgba (screen, x, y, 10, 255, 255, 0, 200) Circle.outline_rgba_aa (screen, x, y, 10, 255, 255, 0, 200) // marcador marca1 = mar1.to_string() marca2 = mar2.to_string() Text.rgba(screen, 280, 10, marca1, 255, 255, 255, 200) Text.rgba(screen, 340, 10, marca2, 255, 255, 255, 200) if marca1 == "21" or marca2 == "21" fin = true while (fin == true) Text.rgba(screen, 260, 220, "JUEGO TERMINADO", 255, 255, 255, 200) Text.rgba(screen, 260, 260, "Inicio: ESC / Otro Juego: J", 255, 255, 255, 200) screen.flip() SDL.Event.wait (out evento) if evento.type == EventType.KEYDOWN if evento.key.keysym.sym == KeySymbol.ESCAPE // reiniciar variables x = 100 y = 240 new_x = 0 new_y = 0 pos1 = 200 pos2 = 200 pos1_new = 0 pos2_new = 0 mar1 = 0 mar2 = 0 fin = false gameover = true saque = true intro = false break if evento.key.keysym.sym == KeySymbol.j // reiniciar variables x = 100 y = 240 new_x = 0 new_y = 0 pos1 = 200 pos2 = 200 pos1_new = 0 pos2_new = 0 mar1 = 0 mar2 = 0 fin = false saque = true break screen.flip() screen.flip() SDL.quit ()
Kataluga
Kataluga es un programa en euskera y castellano creado para tratar la dislexia y otros problemas de adquisición de la lectura y la escritura. Desarrollado para Linux y Windows por Gontzal Uriarte, el código usa y combina distintas librerías, como Gee, Gtk, Pango, Cairo y SDL, y está disponible en GitLab. Además Gontzal es autor del blog Tutorial de Genie / Vala que ha sido una de las referencias importantes de esta Wiki.
Genie progress bar example
Ejemplo para mostrar cómo se podría usar Gtk.ProgressBar mientras se realiza una tarea. Autor: José Fonte (phastmike). Fuente: https://github.com/phastmike/genie-progress-bar-example
- genie-progress-bar.gs
/* -*- Mode: Genie; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */ /* vim: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab : */ /* * genie-progress-bar.gs * * Genie progress bar example - activity mode */ uses Gtk init Gtk.init (ref args) var AppWindow = new MainAppWindow () AppWindow.show_all () Gtk.main () class MainAppWindow : Window progress_bar:Gtk.ProgressBar init title = "Genie Progress Bar example" default_height = 40 default_width = 350 window_position = WindowPosition.CENTER var grid = new Gtk.Grid () progress_bar = new Gtk.ProgressBar () progress_bar.expand = true grid.attach (new Gtk.Label ("Genie, ProgressBar Example"), 0, 0, 1, 1) grid.attach (progress_bar, 0, 1, 1, 1) add (grid) destroy.connect (Gtk.main_quit) Timeout.add (50, pb_pulse); var parser = new Parser () parser.parse_ended.connect (on_parse_ended) parser.parse () def pb_pulse () : bool progress_bar.pulse () return true def on_parse_ended () Gtk.main_quit () class Parser : Object counter:int event parse_ended () def parse () counter = 0 print ("Start parsing..") Timeout.add_seconds (1, work_counter) def work_counter () : bool counter += 1 print ("Counter %d", counter) if counter < 10 return true else print ("Ended parsing..") parse_ended () return false