TkinterMVC

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:

python tkintermvc

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 emailsetter valida o email antes de atribuí-lo ao __emailatributo. Se o e-mail não for válido, será gerado um arquivo ValueError.
  • 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()e hide_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 Appclasse 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.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *