Melhor maneira de estruturar uma aplicação de tkinter [fechado]
o seguinte é a estrutura geral do meu típico programa python tkinter.
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
e funC
irá trazer outra Toplevel
janelas com elementos quando o Utilizador carregar no botão 1, 2, 3.
7 answers
# 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()
As coisas importantes a notar são:
Não Uso cartões especiais. eu importo o pacote como "tk", o que requer que eu prefixe todos os comandos com
tk.
. Isso evita a poluição global do espaço de nomes, além de tornar o código completamente óbvio quando você está usando classes Tkinter, TTK classes, ou alguns de seus próprios.O principal a aplicação é uma classe . Isso lhe dá um espaço de nomes privado para todos os seus callbacks e funções privadas, e apenas geralmente torna mais fácil organizar o seu código. Em um estilo processual você tem que codificar top-down, definindo funções antes de usá-las, etc. Com este método você não faz desde que você não realmente criar a janela principal até o último passo. Prefiro herdar de
tk.Frame
só porque normalmente começo por criar uma moldura, mas não é de forma alguma necessário.
Se a sua aplicação tiver janelas de topo adicionais, recomendo que cada uma delas seja uma classe separada, herdando de tk.Toplevel
. Isso lhe dá todas as mesmas vantagens mencionadas acima -- as janelas são atômicas, elas têm seu próprio espaço de nomes, e o código é bem organizado. Além disso, torna mais fácil colocar cada um em seu próprio módulo, uma vez que o código começa a ficar grande.
Finalmente, você pode querer considerar usar classes para cada parte maior de sua interface. Por exemplo, se você está criando um aplicativo com uma barra de ferramentas, uma área de navegação, uma barra de estado e uma área principal, você pode fazer cada uma dessas classes. Isso torna o seu código principal muito pequeno e 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)
Uma vez que todas essas instâncias compartilham um pai comum, o pai efetivamente se torna a parte "controller" de uma arquitetura model-view-controller. Então, por exemplo, a janela principal poderia colocar algo na barra de Estado chamando self.parent.statusbar.set("Hello, world")
. Isto permite-lhe definir uma interface simples entre os componentes, ajudando a manter o acoplamento a um minimun.
Colocar cada uma das suas janelas de topo na sua própria classe separada dá-Lhe a reutilização de código e uma melhor organização de código. Quaisquer botões e métodos relevantes que estejam presentes na janela devem ser definidos dentro desta classe. Aqui está um exemplo (tirado de aqui):
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 também:
Espero que isso ajude.Aqui está um excelente tutorial sobre o design da GUI tkinter, com alguns exemplos -- http://python-textbok.readthedocs.org/en/latest/Introduction_to_GUI_Programming.html
Aqui está outro exemplo com um padrão de projeto MVC -- https://sukhbinder.wordpress.com/2014/12/25/an-example-of-model-view-controller-design-pattern-with-tkinter-python/
Então o que você pode fazer é escrever classes para estes, em seguida, tem métodos na classe que lidar com comandos para os cliques do botão e assim.
Aqui está um exemplo: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()
Normalmente os programas tk com várias janelas são várias classes grandes e no __init__
Todas as entradas, etiquetas, etc, são criadas e então cada método é lidar com eventos de botão Clique
Não há realmente uma maneira correta de fazê-lo, o que quer que funcione para você e faça o trabalho feito desde que seja legível e você pode facilmente explicá-lo porque se você não pode facilmente explicar o seu programa, provavelmente há uma maneira melhor de fazê-lo.
Olha para pensar em Tkinter.
OOP deve ser a abordagem e frame
deve ser um variável de classe em vez de variável de instância.
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()
Referência: http://www.python-course.eu/tkinter_buttons.php
Provavelmente a melhor maneira de aprender a estruturar o seu programa é lendo o código de outras pessoas, especialmente se é um grande programa para o qual muitas pessoas contribuíram. Depois de olhar para o código de muitos projetos, você deve ter uma idéia de qual o estilo de consenso deve ser.
O Python, como língua, é especial na medida em que existem algumas diretrizes fortes sobre como você deve formatar o seu código. O primeiro é o chamado "Zen de Python":
A beleza é melhor que feio.
- explícito é melhor do que implícito.
Simples é melhor que Complexo. O complexo é melhor do que complicado.- plano é melhor que aninhado.
- esparso é melhor do que denso.
A legibilidade conta. Casos especiais não são especiais o suficiente para quebrar as regras. Embora a praticidade seja melhor que a pureza. Os erros nunca devem passar silenciosamente.- a menos que explicitamente silenciado.
- em face de ambiguidade, recusa a tentação de adivinhar.
Deve haver uma, e de preferência apenas uma, forma óbvia de o fazer. Embora isso possa não ser óbvio, a não ser que sejas Holandês. Agora é melhor do que nunca. Embora nunca seja melhor do que agora. Se a implementação é difícil de explicar, é má ideia. Se a implementação for fácil de explicar, pode ser uma boa ideia.- os espaços de nomes são um boa ideia, vamos fazer mais!
Em um nível mais prático, há PEP8, O Guia de estilo para Python.
Com aqueles em mente, eu diria que o seu estilo de código não se encaixa, particularmente as funções aninhadas. Encontre uma maneira de achatar aqueles para fora, usando classes ou movendo-os em módulos separados. Isto tornará a estrutura do seu programa muito mais fácil de entender.Eu pessoalmente não USO a abordagem orientada objetada, principalmente porque ela a) só fica no caminho; b) você vai Nunca reutilizar isso como um módulo.
Mas algo que não é discutido aqui, é que você deve Usar threading ou multiprocessamento. Sempre. caso contrário, a sua candidatura será horrível.
Faça apenas um teste simples: inicie uma janela e, em seguida, obtenha algum URL ou qualquer outra coisa. as alterações são que a sua IU não será atualizada enquanto a solicitação de rede está acontecendo. Ou seja, a tua janela de aplicação vai estar partida. depende do SO em que você está, mas na maioria das vezes, ele não vai redesenhar, qualquer coisa que você arraste sobre a janela será plastificado sobre ele, até que o processo é de volta para o TK mainloop.