Resumo : neste tutorial, você aprenderá como estruturar uma aplicação Tkinter usando o padrão model-view-controller (MVC).
Introdução ao Tkinter MVC
À medida que sua aplicação cresce, sua complexidade também aumenta. Para tornar o aplicativo mais gerenciável, você pode usar o padrão de design model-view-controller.
O padrão de design MVC permite dividir o aplicativo em três componentes principais: modelo, visualização e controlador. Essa estrutura ajuda você a focar na lógica de cada parte e torná-la mais sustentável, especialmente quando o aplicativo cresce.
O diagrama a seguir ilustra o padrão de design MVC:
Modelo
Um modelo em MVC representa os dados. Um modelo trata da obtenção ou gravação de dados em um armazenamento, como um banco de dados ou arquivo. O modelo também pode conter a lógica para validar os dados para garantir a integridade dos dados.
O modelo não deve depender da visualização e do controlador. Em outras palavras, você pode reutilizar o modelo em outros aplicativos que não sejam do Tkinter, como aplicativos da web e móveis.
Visualizar
Uma visualização é a interface do usuário que representa os dados no modelo. A visualização não se comunica diretamente com o modelo. Idealmente, uma visualização deve ter muito pouca lógica para exibir dados.
A visualização se comunica diretamente com o controlador. Nos aplicativos Tinker, a visualização é a janela raiz que consiste em widgets.
Controlador
Um controlador atua como intermediário entre as visualizações e os modelos. O controlador roteia dados entre as visualizações e os modelos.
Por exemplo, se os usuários clicarem no botão salvar na visualização, o controlador encaminhará a ação “salvar” para o modelo para salvar os dados em um banco de dados e notificar a visualização para exibir uma mensagem.
Exemplo de Tkinter MVC
Daremos um exemplo simples para ilustrar como aplicar o padrão de design MVC em uma aplicação Tkinter:
O aplicativo que você criará contém uma entrada para inserir um email. Ao clicar no botão salvar, o controlador chama o modelo para validar o email.
Se o email for válido, o modelo salva o email em um arquivo de texto e a visualização mostra uma mensagem de sucesso:
Se o e-mail não for válido, a visualização mostrará uma mensagem de erro:
Ocultaremos a mensagem após 3 segundos.
Classe de modelo
O seguinte define a classe Model que possui uma propriedade email:
class Model:
def __init__(self, email):
self.email = email
@property
def email(self):
return self.__email
@email.setter
def email(self, value):
"""
Validate the email
:param value:
:return:
"""
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
if re.fullmatch(pattern, value):
self.__email = value
else:
raise ValueError(f'Invalid email address: {value}')
def save(self):
"""
Save the email into a file
:return:
"""
with open('emails.txt', 'a') as f:
f.write(self.email + '\n')
Linguagem de código: Python ( python )
Como funciona:
- O
email
setter valida o email antes de atribuí-lo ao__email
atributo. Se o e-mail não for válido, será gerado um arquivoValueError
. - O
save()
método grava o email em um arquivo de texto simples. Em aplicativos do mundo real, você pode querer salvá-lo em um banco de dados.
Visualizar
O seguinte define a visualização que mostra um formulário para inserir um email:
class View(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# create widgets
# label
self.label = ttk.Label(self, text='Email:')
self.label.grid(row=1, column=0)
# email entry
self.email_var = tk.StringVar()
self.email_entry = ttk.Entry(self, textvariable=self.email_var, width=30)
self.email_entry.grid(row=1, column=1, sticky=tk.NSEW)
# save button
self.save_button = ttk.Button(self, text='Save', command=self.save_button_clicked)
self.save_button.grid(row=1, column=3, padx=10)
# message
self.message_label = ttk.Label(self, text='', foreground='red')
self.message_label.grid(row=2, column=1, sticky=tk.W)
# set the controller
self.controller = None
def set_controller(self, controller):
"""
Set the controller
:param controller:
:return:
"""
self.controller = controller
def save_button_clicked(self):
"""
Handle button click event
:return:
"""
if self.controller:
self.controller.save(self.email_var.get())
def show_error(self, message):
"""
Show an error message
:param message:
:return:
"""
self.message_label['text'] = message
self.message_label['foreground'] = 'red'
self.message_label.after(3000, self.hide_message)
self.email_entry['foreground'] = 'red'
def show_success(self, message):
"""
Show a success message
:param message:
:return:
"""
self.message_label['text'] = message
self.message_label['foreground'] = 'green'
self.message_label.after(3000, self.hide_message)
# reset the form
self.email_entry['foreground'] = 'black'
self.email_var.set('')
def hide_message(self):
"""
Hide the message
:return:
"""
self.message_label['text'] = ''
Linguagem de código: Python ( python )
Como funciona.
- Primeiro, crie os widgets no
__init__()
método. - Segundo, defina o
set_controller()
método para definir um controlador. - Terceiro, chame o
save()
método do controlador no manipulador de eventos click do botão salvar. - Por fim, defina os métodos
show_error()
,show_success()
ehide_message()
para mostrar/ocultar a mensagem.
Controlador
O seguinte define um controlador:
class Controller:
def __init__(self, model, view):
self.model = model
self.view = view
def save(self, email):
"""
Save the email
:param email:
:return:
"""
try:
# save the model
self.model.email = email
self.model.save()
# show a success message
self.view.show_success(f'The email {email} saved!')
except ValueError as error:
# show an error message
self.view.show_error(error)
Linguagem de código: Python ( python )
Como funciona o controlador.
- Primeiro, atribua o modelo e a visualização no
__init__()
método - Segundo, defina o
save()
método que salva o modelo no arquivo de texto. Se o modelo for salvo com sucesso, mostre uma mensagem de sucesso. Caso contrário, exiba uma mensagem de erro.
Aplicativo
O seguinte define a App
classe que usa as classes Model, View e Controller:
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('Tkinter MVC Demo')
# create a model
model = Model('[email protected]')
# create a view and place it on the root window
view = View(self)
view.grid(row=0, column=0, padx=10, pady=10)
# create a controller
controller = Controller(model, view)
# set the controller to view
view.set_controller(controller)
if __name__ == '__main__':
app = App()
app.mainloop()
Linguagem de código: Python ( python )
Como funciona.
- Primeiro, crie um modelo.
- Segundo, crie uma visualização e coloque-a na janela raiz.
- Terceiro, crie um controlador e configure-o para a visualização.
Junte tudo.
import re
import tkinter as tk
from tkinter import ttk
class Model:
def __init__(self, email):
self.email = email
@property
def email(self):
return self.__email
@email.setter
def email(self, value):
"""
Validate the email
:param value:
:return:
"""
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
if re.fullmatch(pattern, value):
self.__email = value
else:
raise ValueError(f'Invalid email address: {value}')
def save(self):
"""
Save the email into a file
:return:
"""
with open('emails.txt', 'a') as f:
f.write(self.email + '\n')
class View(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# create widgets
# label
self.label = ttk.Label(self, text='Email:')
self.label.grid(row=1, column=0)
# email entry
self.email_var = tk.StringVar()
self.email_entry = ttk.Entry(self, textvariable=self.email_var, width=30)
self.email_entry.grid(row=1, column=1, sticky=tk.NSEW)
# save button
self.save_button = ttk.Button(self, text='Save', command=self.save_button_clicked)
self.save_button.grid(row=1, column=3, padx=10)
# message
self.message_label = ttk.Label(self, text='', foreground='red')
self.message_label.grid(row=2, column=1, sticky=tk.W)
# set the controller
self.controller = None
def set_controller(self, controller):
"""
Set the controller
:param controller:
:return:
"""
self.controller = controller
def save_button_clicked(self):
"""
Handle button click event
:return:
"""
if self.controller:
self.controller.save(self.email_var.get())
def show_error(self, message):
"""
Show an error message
:param message:
:return:
"""
self.message_label['text'] = message
self.message_label['foreground'] = 'red'
self.message_label.after(3000, self.hide_message)
self.email_entry['foreground'] = 'red'
def show_success(self, message):
"""
Show a success message
:param message:
:return:
"""
self.message_label['text'] = message
self.message_label['foreground'] = 'green'
self.message_label.after(3000, self.hide_message)
# reset the form
self.email_entry['foreground'] = 'black'
self.email_var.set('')
def hide_message(self):
"""
Hide the message
:return:
"""
self.message_label['text'] = ''
class Controller:
def __init__(self, model, view):
self.model = model
self.view = view
def save(self, email):
"""
Save the email
:param email:
:return:
"""
try:
# save the model
self.model.email = email
self.model.save()
# show a success message
self.view.show_success(f'The email {email} saved!')
except ValueError as error:
# show an error message
self.view.show_error(error)
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('Tkinter MVC Demo')
# create a model
model = Model('[email protected]')
# create a view and place it on the root window
view = View(self)
view.grid(row=0, column=0, padx=10, pady=10)
# create a controller
controller = Controller(model, view)
# set the controller to view
view.set_controller(controller)
if __name__ == '__main__':
app = App()
app.mainloop()
Linguagem de código: Python ( python )
Resumo
- Use MVC para estruturar os aplicativos Tkinter para torná-los mais organizados.