Archive for the ‘Programming thingies’ Category

Internacionalización con PyQt4

En realidad debería decir traducción, porque la internacionalización incluye además convertir los formatos de fechas, monedas y todo eso, pero bueno, estos son los pasos necesarios para hacer traducciones de distintas partes de un programa usando PyQt4 (la octava maravilla moderna) y Qt Linguist (una herramienta que ya viene incluida cuando se instala PyQt). Yo usé la versión 2.6.4 de Python y la 4.5.1 de PyQt (la 4.7 no me anduvo en Windows 7, a pesar de mis esfuerzos).
 

  1. Marcar los strings a traducir en la aplicación de la siguiente manera:

    1. self.tr() en las clases que heredan de QMainWindow, QDialog o cualquier QObject (pero se suele hacer sobre la ventana)
    2. app.translate(<translation_string>, <translation>)
      
  2.  

  3. Crear un traductor y agregarlo a la aplicación (se pueden crear y agregar tantos como se quiera):

     
    from PyQt4.QtCore import Qlocale, QTranslator
    
    locale = QLocale.system().name()
    app_translator = QTranslator()
    path = "<app_name>_" + locale + ".qm"
     
    if app_translator.load(path):
        app.installTranslator(app_translator)
    

    Si el archivo de traducción va a estar embebido en el archivo de recursos:

     
    import resources #Para que funcione va a haber que llevar a cabo los pasos siguientes:
    
    path = "<app_name>_" + locale
     
    if app_translator.load(path, ":/"):
        app.installTranslator(app_translator)
    
  4.  

  5. Crear un archivo de recursos (ej. resources.qrc) que incluya el o los archivos de traducción:

     
    <!DOCTYPE RCC>
    <RCC version="1.0">
        <qresource>
            <file>staristics_es_AR.qm</file>
            <file><app_name>_<locale>.qm</file>
        </qresource>
    </RCC>
    
  6.  

  7. Crear un archivo pro (ej. .pro) con el siguiente formato:

     
    SOURCES = <main>.py <ventana>.pyw <…>
    TRANSLATIONS = <app_locale>.ts
    
  8.  

  9. Ejecutar el archivo pro desde la línea de comandos:

    directorio_del_proyecto>pylupdate4 -verbose .pro

  10.  

  11. Traducir los strings marcados usando Qt Linguist
  12.  

  13. Compilar el archivo de traducción (File > Release)
  14.  

  15. Compilar el archivo de recursos usando pyrcc4 desde la línea de comandos:

    directorio_del_proyecto>pyrcc4 resources.qrc -o resources.py

 
Actualización de las Traducciones

Cuando se agreguen strings nuevos para traducir en la aplicación, se repiten los pasos del 5 al 8 (modificando el archivo .pro antes de hacerlo si se agregaron archivos .py nuevos que contienen strings para traducir).

Colors of the screen

¿Qué preferís, un hermoso light sky blue o un #d2b48c feo y árido?

Prefiero el light sky blue, porque además de ser más lindo, me lo puedo acordar.
 

Está bueno ponerle colores lindos a nuestros programas y páginas web (o mejor dicho, intentos de programas y páginas web), para nosotros y para quienes los usen. Lo que no es tan lindo es tener que andar acordándose esa cosa tan fea que vimos arriba (para refrescar: eso es un valor hexadecimal que representa un color, donde los dos primeros dígitos son para el rojo, los otros dos para el verde y los últimos para el azul – #rrggbb -).
 

Para eso se inventó la tabla de colores web, que nos da nombres graciosos para acordarnos de números feos.
 

Pero hay un problema: son solamente 256, y con eso no nos alcanza la mayoría de las veces.
 

¿Solución? ¡extender esa tabla! Lo bueno es que en Wikipedia ya está, y muy bien. Así que lo que hice fue usarla para fabricar un tipo de dato enumeratvo en Python (disfrazado de clase, claro), listo para usar (traducirlo a otros lenguajes de programación no requiere demasiado trabajo).
 

La única mala noticia es que para usarlo directamente en css se necesita algún conversor, cosa que no hice. Pero ustedes son mentes brillantes, así que van a saber arreglarlo :)
 

Acá dejo el zip con el módulo PrettyColors y un ejemplo muy simple que muestra como usarlo. ¡Diviértanse con sus apple greens, air force blues y fashion fuschias!

(Sí, el título del post viene de la canción Colors of the Wind)

Free, Like Free Software

Desde las 16:30 de ayer hasta pasaditas las 13:00 de hoy las aulas 5, 6, 7 y 8 de la UNNOBA (que en realidad son una sola) estuvieron ocupadas por estudiantes de Informática ¿se dieron cuenta finalmente las autoridades de que están todos locos y decidieron encerrarlos? ¡nada de eso my friends! tuvieron lugar las 5tas Jornadas de Software Libre. Hubo cinco expositores (y sus acompañantes) que vinieron de Buenos Aires (ciudad) y Santa Fe (no tengo idea) y hablaron de un montón de cosas. Ah, sí, y también de software libre un poco.

Las primeras dos charlas del viernes estuvieron dedicadas a mi amado lenguaje de programación, mi voz hecha código, Python. La tercera fue una especie de debate (bah, eso era lo que se esperaba que fuese), que se hizo improvisadamente por la ausencia de uno de los expositores, y que se convirtió rápidamente en la favorita de las jornadas. El tema era seguridad informática, pero fue dispersándose por bastantes ramas, pasando por el phishing, los robos, los lectores de huellas digitales, la paranoia y la calidad de los choripanes.
 

Después de eso continuamos la discusión afuera, y de eso Agustín hizo aparecer la historia del ladrón que entró a Facebook en la computadora a cuyo dueño le estaba robando y se olvidó de desloguearse. Lo primero que se me vino a la mente fue algo así:
 

Ladrón que twittea
 

pero aparentemente mi idea no fue tan original.

Esta mañana se habló de Ruby, OpenOffice y Asterisk, pero no fue lo mismo que ayer, probablemente porque era un sábado a la mañana y yo estaba dormido como un oso. Ah, y Gastón se ganó un libro de O’Reilly (Oh, really?!), mis felicitaciones.

Hoy llovió mucho, y sigue lloviendo. No me gusta rimar, pero me voy despidiendo.

QT ‘n Plot – Simple Ones

Los gráficos pueden hacer divertidas cosas que no lo son, pueden convertir números fríos que no dicen mucho en cosas que cobran sentido, pueden poner una sonrisa en tu cara y hacerte ver el mundo color de rosa. Bah, no tanto, pero están buenos. Un ejemplo es éste, cortesía de xkcd

fucking_blue_shells

Matplotlib es una librería (vulg. biblioteca) de Python basada en MATLAB, que nos permite hacer super-gráficos de muchas formas y colores, y si andamos con ganas,podemos integrarlos a nuestros programas de todos los días.

Lo que voy a hacer ahora es mostrar cómo trazar un par de gráficos (y cuando digo un par me refiero a 2) e incrustarlos en una aplicación que tiene una GUI basada en PyQt4 (léase Pie Cute). Los gráficos están inspirados en el clásico chiste de Ramón, que tenía un camión y se iba para Gijón. No cuento el chiste acá por respeto al señor Ramón.

 

 

 
Cuando terminemos, la cosa va a quedar algo así:

 
CamionDeRamon

Los requisitos mínimos para poder hacer esto son:

  • Python (yo uso la versión 2.6)
  • Numpy (tiene clases y funciones para trabajar con arreglos)
  • Matplotlib: hay un instalador para windows y una versión independiente de la plataforma (en este último caso va a haber que usar distutils, como lo indiqué en mi post anterior)
  • PyQt
  • (opcional) Un buen entorno de desarrollo, como Eclipse+PyDev, o Wing IDE Professional si andan platudos

Empecemos por el principio:

  1. Importamos las cosas que vamos a usar:
    import sys
    
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    
    import matplotlib
    import matplotlib.pyplot as plot
    
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.figure import Figure
    import numpy as np
    
  2. Creamos e inicializamos la ventana en la que va a transcurrir la acción:
    class FormMain(QMainWindow):
        def __init__(self, parent=None):
            super(FormMain, self).__init__(parent)
    
            self.cc = plot.matplotlib.colors.ColorConverter()
            self.__initialize__()
    
  3. Escribimos el código de inicialización de la ventana:
    def __initialize__(self):
            self.setWindowTitle(QString(u"El camión de Ramón"))
    
            # mainWidget
            mainWidget = QWidget(self)
            self.setCentralWidget(mainWidget)
    
            # layoutMain
            self.layoutMain = QVBoxLayout()
            mainWidget.setLayout(self.layoutMain)
    
            # Figure and canvas configuration
            self.fig = Figure((6.0,6.0), dpi=100,\
    facecolor=self.cc.to_rgb("lightsteelblue"))
            self.fig.subplots_adjust(hspace=0.25)
            self.canvas = FigureCanvas(self.fig)
            self.canvas.setParent(mainWidget)
            self.layoutMain.addWidget(self.canvas)
            self.axes = self.fig.add_subplot(211)
            self.axes.get_xaxis().set_visible(False)
            self.axes2 = self.fig.add_subplot(212)
    
            #layoutSettings
            self.layoutSettings = QHBoxLayout()
            self.layoutMain.addLayout(self.layoutSettings)
    
            #lblInitialSpeed
            self.lblInitialSpeed = QLabel("Velocidad inicial:")
            self.layoutSettings.addWidget(self.lblInitialSpeed)
    
            #spnInitialSpeed
            self.spnInitialSpeed = QSpinBox()
            self.spnInitialSpeed.setValue(6)
            self.spnInitialSpeed.setMaximum(20)
            self.layoutSettings.addWidget(self.spnInitialSpeed)
            self.connect(self.spnInitialSpeed, SIGNAL("valueChanged(int)"),\
    self.UpdatePlots)
    
            self.layoutSettings.addSpacing(12)
    
            #lblAcceleration
            self.lblAcceleration = QLabel(u"Aceleración:")
            self.layoutSettings.addWidget(self.lblAcceleration)
    
            #spnAcceleration
            self.spnAcceleration = QSpinBox()
            self.spnAcceleration.setValue(7)
            self.spnAcceleration.setMaximum(10)
            self.layoutSettings.addWidget(self.spnAcceleration)
            self.connect(self.spnAcceleration, SIGNAL("valueChanged(int)"),\
    self.UpdatePlots)
    
            self.layoutSettings.addSpacing(12)
    
            #lblTime
            self.lblTime = QLabel("Tiempo:")
            self.layoutSettings.addWidget(self.lblTime)
    
            #spnTime
            self.spnTime = QSpinBox()
            self.spnTime.setValue(20)
            self.spnTime.setMinimum(1)
            self.spnTime.setMaximum(20)
            self.layoutSettings.addWidget(self.spnTime)
            self.connect(self.spnTime, SIGNAL("valueChanged(int)"),\
    self.UpdatePlots)
    
            self.layoutSettings.addStretch()
    
            self.UpdatePlots()
    

    Ahora la explicación por partes:

    self.fig = Figure((6.0,6.0), dpi=100, facecolor=self.cc.to_rgb("lightsteelblue"))

    Definimos una figura de 6 pulgadas por 6 pulgadas, con una resolución de 100dpi y un fondo de color lightsteelblue.

    self.fig.subplots_adjust(hspace=0.25)
    

    Establecemos una distancia entre los dos subgráficos igual a 1/4 del tamaño de ellos.

    self.canvas = FigureCanvas(self.fig)
            self.canvas.setParent(mainWidget)
            self.layoutMain.addWidget(self.canvas)
    

    Creamos un Canvas que es el mismísimo QWidget que se va a mostrar en la ventana, y lo agregamos al layout principal.

    self.axes = self.fig.add_subplot(211)
            self.axes.get_xaxis().set_visible(False)
            self.axes2 = self.fig.add_subplot(212)
    

    Creamos los dos subgráficos. De los números que se le pasan a add_subplot, el primer dígito indica el número de filas que va a haber, y el segundo indica el número de columnas (estos dos dígitos tienen que ser iguales en ambos subgráficos, o van a pasar cosas muy desagradables, que ni el más macho de los machos soportaría ver). El tercer dígito indica en qué orden va a aparecer el subgráfico.

    Lo que viene después es código de creación de componentes visuales (Spinboxes y Labels) que se explica solo, lo único que hace falta aclarar es que conectamos las Spinboxes al método UpdatePlots, que vamos a definir a continuación, para que se actualicen los gráficos cada vez que se modifican los valores de velocidad, aceleración y tiempo. Finalmente llamamos a ese método para mostrar los gráficos por primera vez.

  4. Actualizamos los gráficos de velocidad y de posición, y reflejamos los cambios en el Canvas:

    def UpdatePlots(self):
            # Update the subplots
            self.UpdateSpeedPlot()
            self.UpdatePositionPlot()
            self.canvas.draw()
    
  5. Definimos dos pequeños métodos para obtener la velocidad y la posición dados los parámetros especificados por el usuario. Es importante aclarar que como el parámetro time va a ser un arreglo, estos métodos van a devolver arreglos.

    def Speed(self, initialSpeed, acceleration, time):
            return initialSpeed + acceleration * time
        
        def Position(self, initialPosition, initialSpeed, acceleration, time):
            return initialPosition + initialSpeed * time + 0.5 * acceleration \
    * (time ** 2)
    
  6. Cada uno de estos métodos actualiza uno de los gráficos, no explico nada porque ya está todo dicho en los comentarios :) (notarán que antes estaban en inglés y cambiaron súbitamente de idioma, pero es que lo hice para ahorrarme la explicación aparte)

    def UpdateSpeedPlot(self):
            v0 = self.spnInitialSpeed.value()
            a = self.spnAcceleration.value()
            t = self.spnTime.value()
            
            # x es un arreglo con cada segundo, desde 0 a t.
            x = np.arange(0, t + 1)
            # y es un arreglo con la velocidad en cada segundo.
            y = self.Speed(v0, a, x)    
            
            # Limpiamos el gráfico y asignamos lo que va a decir cada eje.
            self.axes.clear()
            self.axes.set_ylabel("Velocidad (m/s)")
            self.axes.set_xlabel("Tiempo (s)")
            # Hacemos que se muestre la cuadrícula.
            self.axes.grid(True)
            
            # Creamos una línea que utilice el arreglo x en el eje x e y en el eje y.
            line = plot.Line2D(x, y, linewidth=2,\
    color=self.cc.to_rgb("yellowgreen"))
            # Agregamos la línea al gráfico y la trazamos.  
            self.axes.add_line(line)
            self.axes.plot()
            
            # Las tres últimas instrucciones son equivalentes en este caso a
            # self.axes.plot(x, y, linewidth=2,\
    color=self.cc.to_rgb("yellowgreen"))
            # pero es más prolijo trabajar cada línea por separado, especialmente cuando
            # trabajamos con varias.
            
            # Fijamos los límites de los ejes coordenados.
            self.axes.set_xlim(0, t)
            self.axes.set_ylim(0, 220)
            
        def UpdatePositionPlot(self):
            v0 = self.spnInitialSpeed.value()
            a = self.spnAcceleration.value()
            t = self.spnTime.value()
            
            # x es un arreglo con cada segundo, desde 0 a t.
            x = np.arange(0, t + 1)
            # y es un arreglo con la posición en cada segundo.
            y = self.Position(0, v0, a, x)
            
            # Limpiamos el gráfico y asignamos lo que va a decir cada eje.
            self.axes2.clear()
            self.axes2.set_ylabel(u"Posición (m)")
            self.axes2.set_xlabel("Tiempo (s)")
            # Hacemos que se muestre la cuadrícula.
            self.axes2.grid(True)
            
            # Creamos una línea que utilice el arreglo x en el eje x e y en el eje y.
            line = plot.Line2D(x, y, linewidth=2,\
    color=self.cc.to_rgb("yellowgreen"))
            # Agregamos la línea al gráfico y la trazamos.   
            self.axes2.add_line(line)
            self.axes2.plot()
            
            # Fijamos los límites de los ejes coordenados.
            self.axes2.set_xlim(0, t)
            self.axes2.set_ylim(0, 2500)       
    

Bueno, ya estamos, acá dejo el código completo, diviértanse haciendo gráficos y no se lastimen :)

#coding=utf-8

import sys

from PyQt4.QtCore import *
from PyQt4.QtGui import *

import matplotlib
import matplotlib.pyplot as plot

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np


class FormMain(QMainWindow):
    def __init__(self, parent=None):
        super(FormMain, self).__init__(parent)
        self.cc = plot.matplotlib.colors.ColorConverter()
        self.__initialize__()
        
        
    def __initialize__(self):
        self.setWindowTitle(QString(u"El camión de Ramón"))
        
        # mainWidget
        mainWidget = QWidget(self)
        self.setCentralWidget(mainWidget)
        
        # layoutMain
        self.layoutMain = QVBoxLayout()
        mainWidget.setLayout(self.layoutMain)
        
        # Figure and canvas configuration 
        self.fig = Figure((6.0,6.0), dpi=100, facecolor=self.cc.to_rgb("lightsteelblue"))
        self.fig.subplots_adjust(hspace=0.25)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(mainWidget)
        self.layoutMain.addWidget(self.canvas)
        self.axes = self.fig.add_subplot(211)
        self.axes.get_xaxis().set_visible(False)
        self.axes2 = self.fig.add_subplot(212)
        
        #layoutSettings
        self.layoutSettings = QHBoxLayout()
        self.layoutMain.addLayout(self.layoutSettings)
        
        #lblInitialSpeed
        self.lblInitialSpeed = QLabel("Velocidad inicial:")
        self.layoutSettings.addWidget(self.lblInitialSpeed)
        
        #spnInitialSpeed
        self.spnInitialSpeed = QSpinBox()
        self.spnInitialSpeed.setValue(6)
        self.spnInitialSpeed.setMaximum(20)
        self.layoutSettings.addWidget(self.spnInitialSpeed)
        self.connect(self.spnInitialSpeed, SIGNAL("valueChanged(int)"), self.UpdatePlots)
        
        self.layoutSettings.addSpacing(12)
        
        #lblAcceleration
        self.lblAcceleration = QLabel(u"Aceleración:")
        self.layoutSettings.addWidget(self.lblAcceleration)
        
        #spnAcceleration
        self.spnAcceleration = QSpinBox()
        self.spnAcceleration.setValue(7)
        self.spnAcceleration.setMaximum(10)
        self.layoutSettings.addWidget(self.spnAcceleration)
        self.connect(self.spnAcceleration, SIGNAL("valueChanged(int)"), self.UpdatePlots)
        
        self.layoutSettings.addSpacing(12)

        #lblTime
        self.lblTime = QLabel("Tiempo:")
        self.layoutSettings.addWidget(self.lblTime)
        
        #spnTime
        self.spnTime = QSpinBox()
        self.spnTime.setValue(20)
        self.spnTime.setMinimum(1)
        self.spnTime.setMaximum(20)
        self.layoutSettings.addWidget(self.spnTime)
        self.connect(self.spnTime, SIGNAL("valueChanged(int)"), self.UpdatePlots)
        
        self.layoutSettings.addStretch()
        
        
        self.UpdatePlots()
        
    def Speed(self, initialSpeed, acceleration, time):
        return initialSpeed + acceleration * time
    
    def Position(self, initialPosition, initialSpeed, acceleration, time):
        return initialPosition + initialSpeed * time + 0.5 * acceleration * (time ** 2)
    
    def UpdatePlots(self):
        # Update the subplots
        self.UpdateSpeedPlot()
        self.UpdatePositionPlot()
        self.canvas.draw()

    def UpdateSpeedPlot(self):
        v0 = self.spnInitialSpeed.value()
        a = self.spnAcceleration.value()
        t = self.spnTime.value()
        
        # x es un arreglo con cada segundo, desde 0 a t.
        x = np.arange(0, t + 1)
        # y es un arreglo con la velocidad en cada segundo.
        y = self.Speed(v0, a, x)    
        
        # Limpiamos el gráfico y asignamos lo que va a decir cada eje.
        self.axes.clear()
        self.axes.set_ylabel("Velocidad (m/s)")
        self.axes.set_xlabel("Tiempo (s)")
        # Hacemos que se muestre la cuadrícula.
        self.axes.grid(True)
        
        # Creamos una línea que utilice el arreglo x en el eje x e y en el eje y.
        line = plot.Line2D(x, y, linewidth=2, color=self.cc.to_rgb("yellowgreen"))
        # Agregamos la línea al gráfico y la trazamos.  
        self.axes.add_line(line)
        self.axes.plot()
        
        # Las tres últimas instrucciones son equivalentes en este caso a
        # self.axes.plot(x, y, linewidth=2, color=self.cc.to_rgb("yellowgreen"))
        # pero es más prolijo trabajar cada línea por separado, especialmente cuando
        # trabajamos con varias.
        
        # Fijamos los límites de los ejes coordenados.
        self.axes.set_xlim(0, t)
        self.axes.set_ylim(0, 220)
        
    def UpdatePositionPlot(self):
        v0 = self.spnInitialSpeed.value()
        a = self.spnAcceleration.value()
        t = self.spnTime.value()
        
        # x es un arreglo con cada segundo, desde 0 a t.
        x = np.arange(0, t + 1)
        # y es un arreglo con la posición en cada segundo.
        y = self.Position(0, v0, a, x)
        
        # Limpiamos el gráfico y asignamos lo que va a decir cada eje.
        self.axes2.clear()
        self.axes2.set_ylabel(u"Posición (m)")
        self.axes2.set_xlabel("Tiempo (s)")
        # Hacemos que se muestre la cuadrícula.
        self.axes2.grid(True)
        
        # Creamos una línea que utilice el arreglo x en el eje x e y en el eje y.
        line = plot.Line2D(x, y, linewidth=2, color=self.cc.to_rgb("yellowgreen"))
        # Agregamos la línea al gráfico y la trazamos.   
        self.axes2.add_line(line)
        self.axes2.plot()
        
        # Fijamos los límites de los ejes coordenados.
        self.axes2.set_xlim(0, t)
        self.axes2.set_ylim(0, 2500)
       

app = QApplication(sys.argv)
frmMain = FormMain()
frmMain.show()
app.exec_()

Another Round Against Python

No tengo nada contra Python. Nada, me encanta y es hermoso, es lindo poder definir conjuntos por comprensión, poder hacer lo que uno quiera con las funciones, y parsear texto en dos patadas. Pero todo se vuelve oscuro y sombrío cuando empieza haber problemas con las distribuciones y uno se pasa medio día leyendo esas mail lists horribles que a veces pueden ser inspiradoras pero que nunca presentan una solución clara para nada.

El otro día me pasó tratando de empaquetar mis programas escritos en Python para que puedan ejecutarse sin ningún problema en Windows. Probé PyInstaller y Py2Exe, después de muchas horas pude hacer andar el segundo, pero ambos presentaban problemas de alguna u otra manera relacionados con Python 2.6, e indirectamente con los elementos del runtime y compiladores de C++ 2008.

Hoy otra vez, a tirarme piedras con distutils, que no me compilaba ninguna de las clases de C vinculadas a alguna biblioteca de Python que quería instalarme, y notificandome con un clarísimo (está titilando el detector de sarcasmo) mensaje que decía “error: none”.
Casi me volví loco buscando por todos lados el VS2008 C++ compiler, tratando de encontrar el problema en los archivos fuente de distutils y haciendo treinta mil cosas frustrantes más.

Al final bajé el instalador para Windows del compilador mingW, lo instalé (por supuesto), agregué \bin al PATH y en el terminal donde estaba tratando de instalar lo que estaba tratando de instalar puse:
python setup.py build –compiler=mingW32 install

Para mi total y absoluta sorpresa, anduvo, y tan sorprendido sigo que todavía ando con la boca abierta.

Conclusiones:

  • Las cosas open-source son muy lindas y me encantan, pero cuando hay problemas, hay problemas (a diferencia del software propietario, que cuando hay problemas, qué se le va a hacé’)
  • Esto lo estoy escribiendo como una forma de recordarme en el futuro cómo hacer si me vuelve a pasar.
  • Debería estar estudiando física y epistemología, chau. :)

P.D.: ¡post número 42!

Double Buffering, It Works

Double buffering is something that has always bugged me, like databases and web programming, not because it’s complicated (at least in a high level language like C#) but because I didn’t understand it (the same happened with those other two things, until one year ago, and now I like them a lot).
It all started some days ago when I had an aha moment and got back to programming, this time a tag cloud control for the .NET framework. The problem was that when I resized the control, and in doing so the tag cloud, some horrible, terrible and annoying flickering of the labels inside of it took place.
I put off that part and keep working on other thing, until today when I decided something had to be done, so I straightened in my chair, took a deep breath, pulled up my sleeves and wrote in the control’s constructor:

this.DoubleBuffered = true;

And that was it, sayonara to the flickering. I must admit I just tested it with a small amount of data, but with that same amount of data and without double buffering, you had to look away while resizing the window because the flickering might leave you blind.

So what’s all this double buffering thing about? instead of outputting each control to the monitor everytime it has to be redrawn, the things that need to be refreshed are stored in the central memory for a little while and then batch-displayed.
Obviously, this explanation is oversimplified, so you know who to ask if you want to know more.
Wikipedia, we love you! :)

Winter Break’s End and AI Debate Part I

Hoy es un típico día de invierno, hace frío y está nublado, pero no llueve. Es además el último día de las vacaciones, tras el cual me esperan unos horarios muy apretados.

Aunque mi estado de ánimo estuvo muy bien algunos cuantos días después del último post, hoy volvió a bajar, pero no tanto. El Viernes, como ya lo había anunciado, tuve el final de Ciencias de la Computación II, con resultados no-tan-buenos pero tampoco deplorables. No me tomaron absolutamente nada de todo lo que había impreso, estudiado y pensado, y en algún lado tenían que terminar todas las horas gastadas, así que acá voy, tratando de explicar de manera muy resumida (el tema da para cientos de posts) el debate sobre la inteligencia artificial.

Empecemos por donde se debe: ¿WTF es la inteligencia Artificial?

Básicamente se llama Inteligencia Artificial (IA – AI, en Inglés) a la capacidad que tiene un dispositivo (generalmente electrónico) de actuar de manera similar a un ser humano pensante. También el termino IA puede referirse a la rama de la ciencia de la computación que se encarga de estudiar modelos computacionales que demuestren esa capacidad, su alcance y sus límites.

Desde hace mucho tiempo en las películas y libros de ciencia ficción se viene planteando la idea de máquinas pensantes, e incluso sintientes: 2001: Una Odisea Espacial, Yo Robot, El Hombre Bicentenario y la película AI (Inteligencia Artificial) dirigida por Spielberg son ejemplos bien conocidos de esto. Sin embargo, todavía no se cumplió ninguna de estas cosas, y ahí es donde empieza el debate: ¿Es posible crear máquinas que piensen, se comporten, sientan y tengan conciencia (aunque sobre esto último tengo mis reservas) como los humanos?

Como siempre pasa en estas cuestiones, hay dos grandes bandos:

  • IA Débil (Weak AI): sostiene que las máquinas no pueden pensar, pero que son capaces de simular muy bien la inteligencia humana. Es de alguna manera el paradigma de facto en la actualidad, y es el que demuestra tener una mayor utilidad. Lo veamos directamente o no, la inteligencia artificial está presente en los videojuegos desde hace mucho tiempo, y conceptos como los de redes neuronales y sistemas expertos (equipos informáticos capaces de simular el conocimiento de un experto en una determinada especialidad) son cada vez más comunes.
  • IA Fuerte (Strong AI): sostiene que todo comportamiento (incluso el del cerebro humano) es un algoritmo (serie finita, ordenada y no-ambigua de pasos) independiente del medio físico sobre el cual se ejecute. Es decir, si se descubriera la forma de traducir el funcionamiento del cerebro a un algoritmo, y se implementara sobre un medio digital, tendríamos un robot, pensante, voilá!

Cada uno de estos puntos de vista tiene sus defensores, y presenta cada uno buenas razones, así que esto va a durar un rato largo (o hasta que ocurra algún tipo de revolución) :)

Las definiciones anteriores son realmente más complejas, pero creo que como las escribí hace que se entiendan un poco mejor.

El post de hoy fue solamente un muy muy breve introducción a esto, y lo dejé acá por ahora para que no se hiciera insoportablemente largo de leer. Pronto voy a escribir parte II, hablando de los defensores más importantes de cada postura y presentando sus argumentos, so stay tuned! ;)