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.

Pergunto-me se esta é a forma correcta de escrever um programa python tkinter. Claro, vai funcionar mesmo que eu escreva assim, mas é a melhor maneira? Parece estúpido, mas quando vejo os códigos que as outras pessoas escreveram, o seu código não é alterado com um monte de funções e principalmente eles têm aulas.

Há alguma estrutura específica que devamos seguir como boas práticas? Como devo planear antes de começar a escrever um programa python?

Eu sei que não existem boas práticas na programação e também não estou a pedi-las. Eu só quero alguns conselhos e explicações para me manter na direção certa enquanto eu estou aprendendo Python sozinho.

Author: nbro, 2013-07-04

7 answers

Defendo uma abordagem orientada para objectivos. Este é o modelo que eu começo com:
# 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.

 161
Author: Bryan Oakley, 2016-12-29 13:50:03

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.
 27
Author: alecxe, 2017-05-23 12:10:29

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/

 6
Author: NargothBond, 2015-05-18 18:39:34
Isto não é uma má estrutura, vai funcionar muito bem. No entanto, você tem que ter funções em uma função para fazer comandos quando alguém clica em um botão ou algo

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.

 3
Author: Serial, 2016-05-25 16:13:53

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()

enter image description here

Referência: http://www.python-course.eu/tkinter_buttons.php

 1
Author: Nik, 2016-07-17 01:52:36

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.
 0
Author: Inbar Rose, 2013-07-04 09:46:05

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.

 -5
Author: gcb, 2015-09-07 19:13:43