Tabla periodica en pyqt en 150 líneas

Enviado por jjgomera el 6 Marzo, 2011 - 16:48.

Se que hay varias aplicaciones en diferentes lenguajes que muestran tablas periódicas, con esta entrada simplemente quiero demostrar la productividad de este lenguaje de programación para la creación de aplicaciones gráficas, en sólo 150 líneas (y seguro que se podría optimizar más) crear algo ya usable.
Ante todo, decir que se necesita tener instalado el paquete python-elemental que es el que nos proporciona los datos de los elementos.
Así que allá vamos con el programa:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from PyQt4 import QtCore, QtGui
import Elemental

class qtelemental(QtGui.QDialog):
    def __init__(self, parent=None):
        super(qtelemental, self).__init__(parent)
        self.setWindowTitle(u"Tabla Periódica")
        self.layout=QtGui.QGridLayout(self)
        self.layout.setSpacing(2)
        for i in range(1, 119):
            b=boton(i, self)
            if Elemental.get_element(i).group.value==0:
                if i<80:
                    j=i-58
                else:
                    j=i-90
                self.layout.addWidget(b, Elemental.get_element(i).period.value+4, j+4, 1, 1)
            elif  i ==57 or i==89:
                self.layout.addWidget(b, Elemental.get_element(i).period.value+4, Elemental.get_element(i).group.value, 1, 1)
            else:
                self.layout.addWidget(b, Elemental.get_element(i).period.value, Elemental.get_element(i).group.value, 1, 1)
        self.layout.addItem(QtGui.QSpacerItem(10,10,QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Fixed),8,0,1,20)
        self.layout.addItem(QtGui.QSpacerItem(10,10,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding),12,0,1,20)

        self.Info=QtGui.QFrame()
        self.layout.addWidget(self.Info, 0, 6, 3, 3)
        self.layoutInfo=QtGui.QGridLayout(self.Info)
        self.layoutInfo.setSpacing(1)
        self.layoutInfo.setContentsMargins(2, 0, 2, 0)
        self.Info.setFrameShape(QtGui.QFrame.StyledPanel)
        self.Info.setFrameShadow(QtGui.QFrame.Raised)
        self.Info.setStyleSheet("background-color: rgb(200, 200, 200);")
        self.numero_atomico = QtGui.QLabel()
        self.numero_atomico.setToolTip(u"Número atómico")
        self.layoutInfo.addWidget(self.numero_atomico, 1, 1, 1, 1)
        font = QtGui.QFont()
        font.setPointSize(11)
        self.simbolo = QtGui.QLabel()
        self.simbolo.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.simbolo.setToolTip(u"Símbolo químico")
        self.simbolo.setFont(font)
        self.layoutInfo.addWidget(self.simbolo, 1, 3, 1, 1)
        self.nombre = QtGui.QLabel()
        self.nombre.setAlignment(QtCore.Qt.AlignCenter)
        font.setWeight(75)
        font.setBold(True)
        self.nombre.setFont(font)
        self.layoutInfo.addWidget(self.nombre, 2, 1, 1, 3)
        font = QtGui.QFont()
        font.setPointSize(8)
        self.peso_atomico = QtGui.QLabel()
        self.peso_atomico.setFont(font)
        self.peso_atomico.setToolTip(u"Peso atómico en g/mol")
        self.layoutInfo.addWidget(self.peso_atomico, 3, 1, 1, 1)
        self.densidad = QtGui.QLabel()
        self.densidad.setFont(font)
        self.densidad.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.densidad.setToolTip(u"Densidad:\n Marrón: Del sólido\n Azul: Del líquido \n Verde: Del vapor")
        self.layoutInfo.addWidget(self.densidad, 3, 3, 1, 1)
        self.Tfusion = QtGui.QLabel()
        self.Tfusion.setFont(font)
        self.Tfusion.setToolTip(u"Punto de fusión en K")
        self.layoutInfo.addWidget(self.Tfusion, 4, 1, 1, 1)
        self.Calorfusion = QtGui.QLabel()
        self.Calorfusion.setFont(font)
        self.Calorfusion.setToolTip(u"Calor de fusión en kJ/mol")
        self.Calorfusion.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.layoutInfo.addWidget(self.Calorfusion, 4, 3, 1, 1)
        self.Tebullicion = QtGui.QLabel()
        self.Tebullicion.setFont(font)
        self.Tebullicion.setToolTip(u"Punto de ebullición en K")
        self.layoutInfo.addWidget(self.Tebullicion, 5, 1, 1, 1)
        self.Calorebullicion = QtGui.QLabel()
        self.Calorebullicion.setFont(font)
        self.Calorebullicion.setToolTip(u"Calor de vaporización en kJ/mol")
        self.Calorebullicion.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.layoutInfo.addWidget(self.Calorebullicion, 5, 3, 1, 1)

        self.configuracion = QtGui.QLabel()
        self.configuracion.setFont(font)
        self.configuracion.setAlignment(QtCore.Qt.AlignCenter)
        self.configuracion.setToolTip(u"Configuración electrónica")
        self.layoutInfo.addWidget(self.configuracion, 6, 1, 1, 3)
       
        self.actualizar(1)

    def actualizar(self, i):
        elemento=Elemental.get_element(i)
        self.numero_atomico.setText(str(elemento.number))
        self.nombre.setText(elemento.name.get_string())
        self.simbolo.setText(elemento.symbol)
        self.peso_atomico.setText(str(round(elemento.atomic_mass.value, 4)))
        if elemento.density_solid.has_value:
            self.densidad.setText(elemento.density_solid.get_string()+" kg/l")
            self.densidad.setStyleSheet("color: #A52A2A;")
        elif elemento.density_liquid.has_value:
            self.densidad.setText(elemento.density_liquid.get_string()+" kg/l")
            self.densidad.setStyleSheet("color: #0000FF;")
        elif elemento.density_gas.has_value:
            self.densidad.setText(elemento.density_gas.get_string()+" g/l")
            self.densidad.setStyleSheet("color: rgb(10, 100, 10);")
        else:
            self.densidad.setText("N/A")
            self.densidad.setStyleSheet("color: #888888;")
        if elemento.melting_point.has_value:
            self.Tfusion.setText(elemento.melting_point.get_string()+" K")
            self.Tfusion.setStyleSheet("color: rgb(0, 0, 200);")
        else:
            self.Tfusion.setText("N/A")
            self.Tfusion.setStyleSheet("color: #888888;")
        if elemento.fusion_heat.has_value:
            self.Calorfusion.setText(elemento.fusion_heat.get_string()+" kJ/mol")
            self.Calorfusion.setStyleSheet("color: rgb(0, 0, 200);")
        else:
            self.Calorfusion.setText("N/A")
            self.Calorfusion.setStyleSheet("color: #888888;")
        if elemento.boiling_point.has_value:
            self.Tebullicion.setText(elemento.boiling_point.get_string()+" K")
            self.Tebullicion.setStyleSheet("color: rgb(200, 0, 0);")
        else:
            self.Tebullicion.setText("N/A")
            self.Tebullicion.setStyleSheet("color: #888888;")
        if elemento.vaporization_heat.has_value:
            self.Calorebullicion.setText(elemento.vaporization_heat.get_string()+" kJ/mol")
            self.Calorebullicion.setStyleSheet("color: rgb(200, 0, 0);")
        else:
            self.Calorebullicion.setText("N/A")
            self.Calorebullicion.setStyleSheet("color: #888888;")
        self.configuracion.setText(elemento.configuration.get_string())
       
class boton(QtGui.QPushButton):
    def __init__(self, i, parent=None):
        super(boton, self).__init__(parent)
        self.setFixedSize(40, 35)
        self.parent=parent
        self.setPalette(QtGui.QPalette(QtGui.QColor(Elemental.get_element(i).series.color.red*255,\
               Elemental.get_element(i).series.color.green*255,\
               Elemental.get_element(i).series.color.blue*255)))
        self.id=i
        self.setText(Elemental.get_element(i).symbol)

    def enterEvent(self, event):
        self.parent.actualizar(self.id)
        event.accept()

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Form = qtelemental()
    Form.show()
    sys.exit(app.exec_())

Y el resultado, una ventana con un indicador en el centro superior donde se van mostrando los valores de las propiedades principales del elemento sobre el que se encuentra el ratón

pantallazo

Imagen de pvaldes
Enviado por pvaldes el 6 Marzo, 2011 - 22:09.

mmmh... muy chulo first

Imagen de m__x_
Enviado por m__x_ el 6 Marzo, 2011 - 22:32.

¡ Lo acabo de probar y me encanta !

Imagen de leafar
Enviado por leafar el 6 Marzo, 2011 - 23:40.

probando.. que bien se ve w2tv, definitivamente python me gusta cada vez mas , ahora lo estoy leyendo.. haber que nuevo aprendo...
Hace poco estaba trabajando en un pequeño programa también usando pyQt, pero por la facilidad generaba el código de las interfaces con Qt designer silbo.
te aconsejaría usar "\" para dividir lineas largas.. así no se saldrán del margen...

Imagen de jjgomera
Enviado por jjgomera el 6 Marzo, 2011 - 23:58.
leafar escribió:

probando.. que bien se ve w2tv, definitivamente python me gusta cada vez mas , ahora lo estoy leyendo.. haber que nuevo aprendo...
Hace poco estaba trabajando en un pequeño programa también usando pyQt, pero por la facilidad generaba el código de las interfaces con Qt designer silbo.
te aconsejaría usar "\" para dividir lineas largas.. así no se saldrán del margen...

gracias, no estoy acostumbrado a usar \ y no me había dado cuenta que había expandía la página, arreglado

Uff, qtdesigner, yo empecé usándolo, de hecho elegí qt sobre gtk por la en principio superioridad de qtdesigner sobre glade. (o por lo menos a primera vista me parecía más fácil de usar). Pero con el tiempo me fui dando cuenta de cosas que no me gustaban:
-Eso de usar setupUI en vez de _init_ no es muy pitónico que digamos
-Lo de separar los textos en el retranslateUi puede parecer una tontería, pero cuando te toca editar el programa para añadir un widget, todo se convierte en un infierno teniendo que añadir entradas en dos partes tan separadas del código, además que para traducir no hace falta tenerlo separado
-Usa el modo antiguo de conexión de señales de pyqt

Puede parecer más cómodo, pero créeme, es cuestión de acostumbrarse, y a la larga es más rápido escribir el código a mano

Imagen de leafar
Enviado por leafar el 7 Marzo, 2011 - 00:36.
jjgomera escribió:

Uff, qtdesigner, yo empecé usándolo, de hecho elegí qt sobre gtk por la en principio superioridad de qtdesigner sobre glade. (o por lo menos a primera vista me parecía más fácil de usar).

tambien empeze a usarlo por la facilidad.. solo generar el archivo.ui luego convertirlo con pyuic.. implementarlo y ya

jjgomera escribió:

Pero con el tiempo me fui dando cuenta de cosas que no me gustaban:
-Eso de usar setupUI en vez de _init_ no es muy pitónico que digamos
-Lo de separar los textos en el retranslateUi puede parecer una tontería, pero cuando te toca editar el programa para añadir un widget, todo se convierte en un infierno teniendo que añadir entradas en dos partes tan separadas del código, además que para traducir no hace falta tenerlo separado
-Usa el modo antiguo de conexión de señales de pyqt

Lo de _init_ no me había dado cuenta (hace muy poco que uso python)... y lo de el antiguo método de manejo de eventos me dio algunos problemas...

jjgomera escribió:

Puede parecer más cómodo, pero créeme, es cuestión de acostumbrarse, y a la larga es más rápido escribir el código a mano

Definitivamente en cuanto tenga tiempo leeré con detenimiento el nuevo manejo de eventos y escribiré la interfaz, además aprovechare para aprender lo de los Layout, y añadirle algunas cosas nuevas a mi programa..

Imagen de arctica
Enviado por arctica el 7 Marzo, 2011 - 07:19.

me encanta ^^

Imagen de Froggy
Enviado por Froggy el 7 Marzo, 2011 - 08:24.

Buenísima ....

Saludos

Imagen de pablocns
Enviado por pablocns el 7 Marzo, 2011 - 14:34.

excelente, me gustaría tener tiempo para hacer este tipo de cosas. Pero por ahora me tengo que dedicar a estudiar la tabla periódica :( y no trabajar sobre ella. saludos

Imagen de cnicolas
Enviado por cnicolas el 10 Marzo, 2011 - 09:59.

Me gusta y mucho, muchas gracias, esta genial clap clap
A ver si tengo tiempo y le echo un vistazo a la programacion.

Imagen de jjgomera
Enviado por jjgomera el 10 Marzo, 2011 - 17:00.

gracias, me alegro de que guste

leafar escribió:

Definitivamente en cuanto tenga tiempo leeré con detenimiento el nuevo manejo de eventos y escribiré la interfaz, además aprovechare para aprender lo de los Layout, y añadirle algunas cosas nuevas a mi programa..

una vez que te acostumbres a usar layout te darás cuenta de lo innecesario de usar qtdesigner