python - w3schools - La mejor forma de estructurar una aplicación tkinter
tkinter python 2.7 install (7)
La siguiente es la estructura general de mi programa python tkinter típico.
def funA():
def funA1():
def funA12():
# stuff
def funA2():
# stuff
def funB():
def funB1():
# stuff
def funB2():
# stuff
def funC():
def funC1():
# stuff
def funC2():
# stuff
root = tk.Tk()
button1 = tk.Button(root, command=funA)
button1.pack()
button2 = tk.Button(root, command=funB)
button2.pack()
button3 = tk.Button(root, command=funC)
button3.pack()
funA
funB
y funC
mostrarán otras ventanas de Toplevel
con widgets cuando el usuario haga clic en el botón 1, 2, 3.
Me pregunto si esta es la forma correcta de escribir un programa python tkinter? Claro, funcionará incluso si escribo de esta manera, pero ¿es la mejor manera? Suena estúpido, pero cuando veo los códigos escritos por otras personas, su código no está mal con muchas funciones y la mayoría tienen clases.
¿Hay alguna estructura específica que debamos seguir como una buena práctica? ¿Cómo debo planificar antes de comenzar a escribir un programa de Python?
Sé que no existen las mejores prácticas en programación y tampoco las estoy pidiendo. Solo quiero algunos consejos y explicaciones para mantenerme en la dirección correcta ya que estoy aprendiendo Python por mí mismo.
Abogo por un enfoque orientado a objetos. Esta es la plantilla con la que comienzo:
# Use Tkinter for python 2, tkinter for python 3
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
<create the rest of your GUI here>
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Las cosas importantes para notar son:
No uso una importación de comodines. Importación el paquete como "tk", que requiere que prefijo todos los comandos con
tk.
. Esto evita la contaminación global del espacio de nombres, además de que hace que el código sea completamente obvio cuando está utilizando clases Tkinter, clases ttk o algunas propias.La aplicación principal es una clase . Esto le proporciona un espacio de nombres privado para todas sus devoluciones de llamadas y funciones privadas, y generalmente hace que sea más fácil organizar su código. En un estilo de procedimiento, tiene que codificar top-down, definir funciones antes de usarlas, etc. Con este método no lo hace, ya que no crea la ventana principal hasta el último paso. Prefiero heredar de
tk.Frame
solo porque normalmente comienzo creando un marco, pero de ninguna manera es necesario.
Si su aplicación tiene ventanas adicionales a nivel superior, recomiendo hacer de cada una de ellas una clase separada, heredando de tk.Toplevel
. Esto le brinda todas las ventajas mencionadas anteriormente: las ventanas son atómicas, tienen su propio espacio de nombres y el código está bien organizado. Además, hace que sea fácil poner cada uno en su propio módulo una vez que el código comienza a ser grande.
Por último, es posible que desee considerar el uso de clases para cada parte importante de su interfaz. Por ejemplo, si está creando una aplicación con una barra de herramientas, un panel de navegación, una barra de estado y un área principal, puede hacer cada una de esas clases. Esto hace que su código principal sea bastante pequeño y fácil de entender:
class Navbar(tk.Frame): ...
class Toolbar(tk.Frame): ...
class Statusbar(tk.Frame): ...
class Main(tk.Frame): ...
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.statusbar = Statusbar(self, ...)
self.toolbar = Toolbar(self, ...)
self.navbar = Navbar(self, ...)
self.main = Main(self, ...)
self.statusbar.pack(side="bottom", fill="x")
self.toolbar.pack(side="top", fill="x")
self.navbar.pack(side="left", fill="y")
self.main.pack(side="right", fill="both", expand=True)
Dado que todas esas instancias comparten un elemento primario común, el elemento primario se convierte efectivamente en la parte "controladora" de una arquitectura modelo-vista-controlador. Entonces, por ejemplo, la ventana principal podría colocar algo en la barra de estado al llamar a self.parent.statusbar.set("Hello, world")
. Esto le permite definir una interfaz simple entre los componentes, ayudando a mantener el acoplamiento al mínimo.
Al colocar cada una de las ventanas de nivel superior en su propia clase separada, se obtiene una nueva utilización del código y una mejor organización del código. Todos los botones y métodos relevantes que están presentes en la ventana se deben definir dentro de esta clase. Aquí hay un ejemplo (tomado de here ):
import tkinter as tk
class Demo1:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.button1 = tk.Button(self.frame, text = ''New Window'', width = 25, command = self.new_window)
self.button1.pack()
self.frame.pack()
def new_window(self):
self.newWindow = tk.Toplevel(self.master)
self.app = Demo2(self.newWindow)
class Demo2:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.quitButton = tk.Button(self.frame, text = ''Quit'', width = 25, command = self.close_windows)
self.quitButton.pack()
self.frame.pack()
def close_windows(self):
self.master.destroy()
def main():
root = tk.Tk()
app = Demo1(root)
root.mainloop()
if __name__ == ''__main__'':
main()
Ver también:
Espero que ayude.
Aquí hay un excelente tutorial sobre el diseño de GUI de tkinter, con un par de ejemplos - http://python-textbok.readthedocs.org/en/latest/Introduction_to_GUI_Programming.html
Aquí hay otro ejemplo con un patrón de diseño MVC: https://sukhbinder.wordpress.com/2014/12/25/an-example-of-model-view-controller-design-pattern-with-tkinter-python/
Esta no es una mala estructura; Funcionará bien. Sin embargo, debe tener funciones en una función para hacer comandos cuando alguien hace clic en un botón o algo
Entonces, lo que podrías hacer es escribir clases para estos y luego tener métodos en la clase que manejan los comandos para los clics del botón y demás.
Aquí hay un ejemplo:
import tkinter as tk
class Window1:
def __init__(self, master):
pass
# Create labels, entries,buttons
def button_click(self):
pass
# If button is clicked, run this method and open window 2
class Window2:
def __init__(self, master):
#create buttons,entries,etc
def button_method(self):
#run this when button click to close window
self.master.destroy()
def main(): #run mianloop
root = tk.Tk()
app = Demo1(root)
root.mainloop()
if __name__ == ''__main__'':
main()
Por lo general, los programas tk con múltiples ventanas son múltiples clases grandes y en __init__
todas las entradas, etiquetas, etc. y luego cada método es para manejar los eventos de clic de botón
No existe una forma correcta de hacerlo, lo que sea que funcione para usted y hace el trabajo siempre que sea legible y puede explicarlo fácilmente porque si no puede explicar fácilmente su programa, probablemente haya una mejor manera de hacerlo. .
Eche un vistazo a Pensar en Tkinter .
OOP debe ser el enfoque y el frame
debe ser una variable de clase en lugar de una variable de instancia .
from Tkinter import *
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(frame,
text="QUIT", fg="red",
command=frame.quit)
self.button.pack(side=LEFT)
self.slogan = Button(frame,
text="Hello",
command=self.write_slogan)
self.slogan.pack(side=LEFT)
def write_slogan(self):
print "Tkinter is easy to use!"
root = Tk()
app = App(root)
root.mainloop()
Referencia: http://www.python-course.eu/tkinter_buttons.php
Personalmente, no uso el enfoque orientado objetado, principalmente porque a) solo se interpone en el camino; b) nunca volverás a utilizar eso como un módulo.
pero algo que no se discute aquí, es que debes usar threading o multiprocesamiento. Siempre. de lo contrario, su solicitud será horrible.
simplemente haga una prueba simple: comience una ventana, y luego busque alguna URL o cualquier otra cosa. Los cambios son que su UI no se actualizará mientras se realiza la solicitud de la red. Es decir, su ventana de aplicación se romperá. dependa del sistema operativo en el que se encuentre, pero la mayoría de las veces no volverá a dibujar, todo lo que arrastre por la ventana quedará grabado en él, hasta que el proceso vuelva al TK mainloop.
Probablemente la mejor manera de aprender cómo estructurar su programa es leyendo el código de otras personas, especialmente si se trata de un programa grande al que han contribuido muchas personas. Después de mirar el código de muchos proyectos, debe hacerse una idea de cuál debería ser el estilo de consenso.
Python, como idioma, es especial en cuanto a que hay algunas pautas sólidas sobre cómo debe formatear su código. El primero es el llamado "Zen de Python":
- Hermoso es mejor que feo.
- Explícito es mejor que implícito.
- Simple es mejor que complejo.
- Complejo es mejor que complicado.
- Flat es mejor que anidado.
- Sparse es mejor que denso.
- La legibilidad cuenta
- Los casos especiales no son lo suficientemente especiales como para romper las reglas.
- Aunque la practicidad supera a la pureza.
- Los errores nunca deberían pasar silenciosamente.
- A menos que esté explícitamente silenciado.
- En vista de la ambigüedad, rechace la tentación de adivinar.
- Debería haber una, y preferiblemente solo una, forma obvia de hacerlo.
- Aunque de esa manera puede no ser obvio al principio a menos que seas holandés.
- Ahora es mejor que nunca.
- Aunque nunca es a menudo mejor que ahora.
- Si la implementación es difícil de explicar, es una mala idea.
- Si la implementación es fácil de explicar, puede ser una buena idea.
- Los espacios de nombres son una gran idea: ¡hagamos más de eso!
En un nivel más práctico, está PEP8 , la guía de estilo para Python.
Con eso en mente, diría que su estilo de código no encaja, particularmente las funciones anidadas. Encuentre una manera de alisarlos, ya sea mediante el uso de clases o moviéndolos a módulos separados. Esto hará que la estructura de su programa sea mucho más fácil de entender.