Tk en Python usando OOP

Iniciado por alvk4r, 3 Noviembre 2008, 16:43 PM

0 Miembros y 1 Visitante están viendo este tema.

alvk4r

Bueno que hace tiempo no posteo nada... realmente he estado bastante liado con el trabajo... Interesante este curso, lastima que no siga... No obstante aportare mi granito..

Las interfaces graficas, por un problema de reusabilidad, organizacion y otras razones deben programarse utilizando un modelo orientado a objetos.

Nota sobre los Frames: Los frames son widgets que pueden contener otros widgets como botones, etiquetas, etc. Permiten agrupar controles.

Código (python) [Seleccionar]

from Tkinter import *
class Application(Frame):
  """ GUI application which counts button clicks. """
  def __init__(self, master):
    """ Inicializa el Frame. """
    Frame.__init__(self, master)
    self.grid()
    self.bttn_clicks = 0    # the number of button clicks
    self.create_widgets()
 
  def create_widgets(self):
    """ Crea widgets. """
    self.lbl = Label(self, text="Total Clicks: 0")
    self.lbl.grid()
   
    self.bttn = Button(self, text="ClickMe", command=self.update_count)
    self.bttn.grid()
 
  def update_count(self):
    """ Increase click count and display new total. """
    self.bttn_clicks += 1
    self.lbl["text"] = "Total Clicks: "+ str(self.bttn_clicks)
   
root = Tk()
root.title("Click Counter")
root.geometry("200x50")

app = Application(root)

root.mainloop()


En este ejemplo se muestra como manejar Frames de forma independiente. En vez de heredar la clase Frame heredamos Tk.
Código (python) [Seleccionar]

from Tkinter import *

class FrameMan(Tk):
  """ Gestion de Frames. """
  def __init__(self):
    """ Initialize the frame. """
    Tk.__init__(self)
    self.grid()
   
    self.title("Simple Calculator.")
    self.resizable(width = 0, height = 0)
    self.geometry("200x75")
   
    self.result = 0
    self.createWidgets()
   
  def createWidgets(self):
    """ Creamos el Frame y demas controles hijos. """
    self.myFrame1 = Frame(self)
    self.myFrame2 = Frame(self)
    self.myFrame1.grid(row = 0, column = 0)
    self.myFrame2.grid(row = 0, column = 1)
   
    self.Label1 = Label(self.myFrame1, text = "Este es el Frame 1")
    self.Label2 = Label(self.myFrame2, text = "Este es el Frame 2")
    self.Label1.grid()
    self.Label2.grid()
   
    self.Button1 = Button(self, text = "Dest 1", command = self.destF1)
    self.Button2 = Button(self, text = "Dest 2", command = self.destF2)
    self.Button1.grid(row = 1, column = 0)
    self.Button2.grid(row = 1, column = 1)
   
  def runApp(self):
    """ Ejecutamos la aplicacion. """
    self.mainloop()

  def destF1(self):
    self.myFrame1.destroy()
 
  def destF2(self):
    self.myFrame2.destroy()
   
root = FrameMan().runApp()


Por ultimo dos variantes de un mismo programa. Es una calculadora simple donde escogemos la operacion a realizar. Buen ejemplo, puesto que muestra el uso de diferentes controles, asi como el uso del layout manager grid().

Variante 1:

Código (python) [Seleccionar]

from Tkinter import *

def showWindows():
  root = Tk()
  root.title("Simple Calculator.")
  root.resizable(width = 0, height = 0)
  root.geometry("370x75")
  Application(root)
  root.mainloop()

class Application(Frame):
  """ Calculadora simple usando Tkinter. """
  def __init__(self, master):
    """ Initialize the frame. """
    Frame.__init__(self, master)
    self.grid()
    self.result = 0
    self.create_widgets()
 
  def create_widgets(self):
    """ Creamos controles hijos. """
    self.numb1 = Entry(self)
    self.numb1.grid(row = 0, column = 0, columnspan = 2, sticky = E)
    self.numb1.insert(0, "0")
   
    self.lblop = Label(self, text="?")
    self.lblop.grid(row = 0, column = 1, sticky = E)
   
    self.numb2 = Entry(self, text = "0")
    self.numb2.grid(row = 0, column = 2, columnspan=2, sticky = E)
    self.numb2.insert(0, "0")
   
    self.lblEqual = Label(self, text = "=")
    self.lblEqual.grid(row = 0, column = 5, sticky = E)
   
    self.lblResult = Label(self, text = "Result")
    self.lblResult.grid(row = 0, column = 6, sticky = E)
   
    self.opr = StringVar()
    self.opr.set = "?"
   
    self.optSum = Radiobutton(self,
                              text = "+",
                              variable = self.opr,
                              value = "+",
                              command = self.upd_opr
                              ).grid(row = 1, column = 0, sticky = W)
                             
    self.optRest = Radiobutton(self,
                              text = "-",
                              variable = self.opr,
                              value = "-",
                              command = self.upd_opr
                              ).grid(row = 2, column = 0, sticky = W)
   
    self.optMult = Radiobutton(self,
                              text = "*",
                              variable = self.opr,
                              value = "*",
                              command = self.upd_opr
                              ).grid(row = 1, column = 1, sticky = W)
   
    self.optDiv = Radiobutton(self,
                              text = "/",
                              variable = self.opr,
                              value = "/",
                              command = self.upd_opr
                              ).grid(row = 2, column = 1, sticky = W)
   
    self.btnCalc = Button(self, text = "Calcular", command = self.calc)
    self.btnCalc.grid(row = 1, column = 2, rowspan = 2, sticky = E)
 
  def upd_opr(self):
    self.lblop["text"] = self.opr.get()
   
  def calc(self):
    """ Realizamos el calculo escogido. """
    if self.opr.get() == "+":
      self.result = float(self.numb1.get()) + float(self.numb2.get())
      self.lblResult["text"] = self.result
    elif self.opr.get() == "-":
      self.result = float(self.numb1.get()) - float(self.numb2.get())
      self.lblResult["text"] = self.result
    elif self.opr.get() == "*":
      self.result = float(self.numb1.get()) * float(self.numb2.get())
      self.lblResult["text"] = self.result
    elif self.opr.get() == "/":
      self.result = float(self.numb1.get()) / float(self.numb2.get())
      self.lblResult["text"] = self.result

showWindows()


Variante 2:

Código (python) [Seleccionar]

from Tkinter import *

class SimpleCalc(Tk):
  """ Calculadora simple usando Tkinter. """
  def __init__(self):
    """ Initialize the frame. """
    Tk.__init__(self)
    self.grid()
   
    self.title("Simple Calculator.")
    self.resizable(width = 0, height = 0)
    self.geometry("370x75")
   
    self.result = 0
    self.createWidgets()
 
  def createWidgets(self):
    """ Creamos el Frame y demas controles hijos. """
    self.myFrame = Frame(self)
    self.myFrame.grid()
   
    self.numb1 = Entry(self.myFrame)
    self.numb1.grid(row = 0, column = 0, columnspan = 2, sticky = E)
    self.numb1.insert(0, "0")
   
    self.lblop = Label(self.myFrame, text="?")
    self.lblop.grid(row = 0, column = 1, sticky = E)
   
    self.numb2 = Entry(self.myFrame, text = "0")
    self.numb2.grid(row = 0, column = 2, columnspan=2, sticky = E)
    self.numb2.insert(0, "0")
   
    self.lblEqual = Label(self.myFrame, text = "=")
    self.lblEqual.grid(row = 0, column = 5, sticky = E)
   
    self.lblResult = Label(self.myFrame, text = "Result")
    self.lblResult.grid(row = 0, column = 6, sticky = E)
   
    self.opr = StringVar()
    self.opr.set = "?"
   
    self.optSum = Radiobutton(self.myFrame,
                              text = "+",
                              variable = self.opr,
                              value = "+",
                              command = self.updOpr
                              ).grid(row = 1, column = 0, sticky = W)
                             
    self.optRest = Radiobutton(self.myFrame,
                              text = "-",
                              variable = self.opr,
                              value = "-",
                              command = self.updOpr
                              ).grid(row = 2, column = 0, sticky = W)
   
    self.optMult = Radiobutton(self.myFrame,
                              text = "*",
                              variable = self.opr,
                              value = "*",
                              command = self.updOpr
                              ).grid(row = 1, column = 1, sticky = W)
   
    self.optDiv = Radiobutton(self.myFrame,
                              text = "/",
                              variable = self.opr,
                              value = "/",
                              command = self.updOpr
                              ).grid(row = 2, column = 1, sticky = W)
   
    self.btnCalc = Button(self.myFrame, text = "Calcular", command = self.calcRes)
    self.btnCalc.grid(row = 1, column = 2, rowspan = 2, sticky = E)
   
    self.btnSal = Button(self.myFrame, text = "Salir", command = self.quitApp)
    self.btnSal.grid(row = 1, column = 3, rowspan = 2, sticky = E)
 
  def updOpr(self):
    self.lblop["text"] = self.opr.get()
   
  def runApp(self):
    """ Ejecutamos la aplicacion. """
    self.mainloop()
   
  def quitApp(self):
    """ Funcion que llama al evento destroy() del objeto Tk. """
    self.quit()
   
  def calcRes(self):
    """ Realizamos el tipo de calculo escogido. """
    if self.opr.get() == "+":
      self.result = float(self.numb1.get()) + float(self.numb2.get())
      self.lblResult["text"] = self.result
    elif self.opr.get() == "-":
      self.result = float(self.numb1.get()) - float(self.numb2.get())
      self.lblResult["text"] = self.result
    elif self.opr.get() == "*":
      self.result = float(self.numb1.get()) * float(self.numb2.get())
      self.lblResult["text"] = self.result
    elif self.opr.get() == "/":
      self.result = float(self.numb1.get()) / float(self.numb2.get())
      self.lblResult["text"] = self.result
    else:
      tkMessageBox.showerror(title="Error!!!", message="Escoja un operador.").show()
     
#Corremos la aplicacion
root = SimpleCalc().runApp()


El metodo OOP o POO, como prefieran es harto flexible, y aunque en algunos casos complica la solucion a un problema, cuando se trata de interfaces graficas y eventos se hace conveniente su uso.
Para dudas respecto al codigo, busquen la(s) palabra(s) clave de la sección de codigo que despierte dudas en la ayuda de Python.
El poder corrompe, el poder absoluto corrompe absolutamente.

alvk4r

Al moderador si puede hacerme el favor de mover el tema a donde corresponde, no me di cuenta de en que sección estaba.
El poder corrompe, el poder absoluto corrompe absolutamente.

^Tifa^

CitarLas interfaces graficas, por un problema de reusabilidad, organizacion y otras razones deben programarse utilizando un modelo orientado a objetos.

Depende el lenguaje en el cual trabajamos y la libreria de widgets que le implementamos.   :-*

alvk4r

Cita de: ^TiFa^ en  4 Noviembre 2008, 13:48 PM
Depende el lenguaje en el cual trabajamos y la libreria de widgets que le implementamos.   :-*

Es logico que estoy hablando de Python y Tk.

Aunque no soy partidario de usar OOP para todo, en muchos casos este modelo complica la solucion a un problema, y Python es flexible en cuanto a la decision de utilizar o no dicho modelo...
No conozco otra forma de implementar widgets, ni utilizando otra biblioteca de graficos ni ningun otro lenguaje... La forma en que estan programadas las bibliotecas de widgets te obliga a utilizar OOP (Me refiero solamente a lenguages imperativos, no funcionales ni logicos).
Aunque utilizes funciones para crear programas, cuando declares:
Código (python) [Seleccionar]
\
...
milabel = Label(miFrame, text = "Mi ETIQUETA")
...


Estas creando un objeto Label que hereda la clase Label().
Por ello es bueno organizar tu propio codigo en clases y demas...

Si utilizaras wxWidgets, QT o cualquier otra biblioteca gráfica, con C++, por ejemplo sucede lo mismo...
Si utilizaras la biblioteca Swing de Java, con Java o Jython... pues igual... te ves obligado  a trabajar con OOP.

Igual esta es mi opinion, si tienes algun ejemplo que mostrarme, relacionado a lo que dices, te lo agradeceria... Favor circunscribete al tema de Python... aunque utilices cualquier otra biblioteca grafica...
El poder corrompe, el poder absoluto corrompe absolutamente.

^Tifa^

Creo que es bastante notable que este post habla de python/tk y OOP   ::)

Pero cuando hice referencia a este punto :

CitarLas interfaces graficas, por un problema de reusabilidad, organizacion y otras razones deben programarse utilizando un modelo orientado a objetos.

Y observando tu codigo posteado, con classes implementadas y eso...

Me acorde de C/GTK donde aun utilizando objetos que son los widgets, yo no puedo organizar mi codigo en classes.. sino llamando funciones en la mayoria de los casos...

Hablaba mas del desarrollo del codigo propio en si, que el funcionamiento de la libreria grafica. Ya que segun comentas, debido a que las librerias graficas manejan objetos la mejor manera de programar entonces es usando POO??? Y si el lenguaje que el usuario esta utilizando no tiene capacidad para ser POO??

A mi tampoco me gusta mucho la POO, como tu, digo que esta aqui para complicar las cosas.

alvk4r

Si utilizas algun IDE este crea e implementa las clases de forma automatica... y aunque no utilices una estructura de clases en tu aplicacion, en u nfinal esas funciones son metodos de clase...
Claro me diras que C no usa clases... no es C++ blah, blah,blah...
Y aunque se aleja del tema del Post, no he visto widgets utilizando ansi C o C en su forma pura...

Si tienes algun ejemplo mandamelo... pues me gusta conocer temas nuevos...
El poder corrompe, el poder absoluto corrompe absolutamente.

^Tifa^

#6

Ok, usare de ejemplo C y GTK+ que es lo que conozco un pelin y no puedo orientar a C a POO. Tienes razon al decir que las librerias graficas estan orientadas a objetos de hecho en el caso de Gtk+ digamos que su objeto principal es GtkObject. Pero que te digo en C, hasta lo poco que he podido ver nunca he tenido que llamar o dar uso directo de GtkObject. O sea si hubiera una manera en C/GTK de yo mapear dentro de una clase (Si C soportara POO como C++) el GtkObject me ahorraria muchas lineas de codigo. me evitara tener que memorizarme y utilizar tantos Macros para cada constructor en C o sea no puedo tener en C/GTK una classe con objetitos dentro sino que debo por cada objeto crear un constructor incluso al objeto principal 'window' debo crearlo independiente nuevo por ejemplo ::

GtkWindow *ventana;
GtkWindow *boton;
GtkWindow *palabra;

O sea que pesado no :/ fuera distinto si pudiera yo hacer algo tipo :

my ventana = new MainWindow;
boton = $ventana->boton(-text bla, -command bla);
palabra = $ventana->palabra(-text bla);

Y esto sin contar los dichosos MACROS predefinidos que tiene Gtk+ en C que hay que memorizarselos todos para ir declarando y llamando los objetos de cada constructor por ejemplo para GtkWindow *ventana :

GTK_WINDOW_TOPLEVEL  quisiera mapear 'GTK_' a alguna clase que se yo, digamos la clase Pepe.

Pepe::WINDOW_TOPLEVEL.
Pepe::Button
Pepe::Label

Y no ::

boton = GTK_BUTTON_NEW;
palabra = GTK_LABEL_NEW;

O sea en C/GTK aun utilizando la libreria de widgets GTK orientada a objetos lol claro... todos los widgets hay que ir practicamente linkeandolos llamando funciones independientemente cada vez. Incluso para empaquetar el widget final es un suplicio :
Y todo porque depende mucho si el lenguaje que estas usando soporta o no POO, no hablo explicitamente de la libreria grafica, sino del lenguaje en si al cual le integramos la libreria grafica.

Mira por ejemplo el empaquetamiento de un widget en C/GTK

GtkWidget *window;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

gtk_container_border_width (GTK_CONTAINER (window), 10);

1 - constructor
2 - declaracion objeto nuevo
3 - empaquetando dicho objeto

EN un lenguaje que soporte POO como C++, Python, etc harias algo tipo :

ventana = Pepe::Window.new(Pepe::WINDOW_TOPLEVEL)
ventana.border_width = 10

Donde gastas mas lineas? En el rustico C/Gtk llamando funciones ordinarias en macros predefinidos de la libreria grafica o en un lenguaje POO usando librerias graficas???



43H4FH44H45H4CH49H56H45H

#7
Viendo los post anteriores dejo mi opinión...

No se puede debatir las ventajas de la POO y su aplicación con una base tan frágil como la que han mostrado en todo este hilo.
Las ventajas de la POO (relacionada con el Paradigma Basado en Objetos) solo pueden demostrarse en la creación de sistemas o aplicaciones de determinada complejidad en la cual se utilizan metodologías como El Proceso Unificado de Rational y el Lenguaje Unificado de Modelado UML, además de otras tecnologías y tipos de Ingeniería.
Paso de explicar cosas como el Modelamiento Visual y Proceso de Desarrollo de Software, Notaciones y Dentro de UML distintos tipos de diagramas los cuales  son utilizados (dependiendo del tipo de diagrama) por los Ingenieros de Control de calidad, Arquitectos, usuarios, analistas, diseñadores, gerentes y otros del Sistema.

Por tanto es difícil que lleguen a una conclusión válida con sus argumentos, conocimientos y experiencia.

Nota.- El lenguaje C puede adoptar la POO (mediante medidas sistemáticas) aunque no soporte algunas de las características avanzadas que soportan los lenguajes de programación orientada a objetos.

-R IP
:0100
-A 100 
2826:0100 MOV AH,09
2826:0102 MOV DX,109
2826:0105 INT 21
2826:0105 MOV AH,08
2826:0105 INT 21
2826:0107 INT 20
2826:0109 DB 'MI NICK ES CODELIVE.$' 
2826:0127 
-R BX
:0000
-R CX
:20
-N CODELIVE.COM
-W

^Tifa^

Hola amigo.

Aqui ninguno de los 2 estamos debatiendo las ventajas de la POO. Creo que tus explicaciones son buenas Ok, pero si aqui no estabamos devatiendo eso :/  otra cosita que veo mal en tu comentario es que juzgues a 2 personas sin conocerla en cuanto a sus inferiores niveles de conocimientos segun tu y la POO.

Lo mio particularmente no va dirigido a la POO, lo he dicho muchas veces en otros posts, y no trabajo con ninguna POO, y espero no hacerlo nunca, porque para mis gustos particulares esa metodologia no aplica. Aqui se hablaba porque veo que estas deviiandote un poco, aqui hablabamos sobre mezclar librerias graficas y lenguajes y que esto obligase o no a utilizar una influencia POO, lo cual no siempre es cierto dependiendo el lenguaje que se utilize que fue lo que quize aclarar... nada mas, en ningun momento se hablo sobre ventajas de POO.

Yo se que en C se puede semi-implementar una similitud hacia POO pero eso no es el estandar de C ni el lenguaje esta predefinido para eso, eos es como querer hacer un bindings de algo que no vino para funcionar asi... para hacer ese espaghetti mejor se utiliza algo que lo soporte 100% como C++.

Es solo mi opinion, un saludo y no desvien el tema.

alvk4r

Completamente de acuerdo... Bravo ^TIFA^. Añadir que los paradigmas y filosofias son solo eso, paradigmas y filosofias... nada mas... mencionaste UML, sin embargo yo en mi trabajo debo desarrollar aplicaciones BPM que conllevan manejo masivo de datos, y aunque pudiera hacerlo con UML (me refiero al modelado de datos), me es mas ventajosos emplear ORM... Por cierto... que UML no es un lenguaje en si, ni una filosofia o ingeniería de desarrollo.. solo es un estándar que permite representar graficamente, entre otras cosas, clases y objetos... se aviene de lo mejor para modelar soluciones POO. Y en cuanto a otros tipos de ingeniería, no has hecho sino referencia a modelos utilizados ampliamente en temas de ingeniería de software (y actualmente es este mi fuerte por su vinculacion al Business Process Management), asi que no juzqgues así no mas.

Por ultimo recomiendo a los que usen Python experimentar con el Boa Constructor... para mi el mejor IDE hasta ahora...

^TIFA^ me hablaste del Ruby, siempre he querido experimentar con el, pero me falta tiempo... Si pudieras hacerte un tiempito... en python implementar GTK es mas simple... ya me tengo que ir... pronto te dejo un ejemplo... ;)
El poder corrompe, el poder absoluto corrompe absolutamente.