Najlepszy sposób na uporządkowanie aplikacji tkinter [zamknięty]

Poniżej znajduje się ogólna struktura mojego typowego programu Tkinter w Pythonie.

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 i funC wyświetli kolejne Toplevel okna z widżetami po kliknięciu przycisku 1, 2, 3.

Zastanawiam się, czy to dobry sposób na napisanie programu Tkinter w Pythonie? Jasne, to zadziała, nawet jeśli napiszę w ten sposób, ale czy jest to najlepszy sposób? To brzmi głupio, ale jak widzę kody napisane przez innych ludzi, ich kod nie jest pomieszany z wieloma funkcjami i głównie oni masz zajęcia.

Czy jest jakaś konkretna struktura, którą powinniśmy stosować jako dobrą praktykę? Jak planować przed rozpoczęciem pisania programu w Pythonie?

Wiem, że nie ma czegoś takiego jak najlepsze praktyki w programowaniu i o to też nie proszę. Chcę tylko kilku porad i wyjaśnień, aby utrzymać mnie w dobrym kierunku, ponieważ sam uczę się Pythona.

Author: nbro, 2013-07-04

7 answers

Opowiadam się za podejściem zorientowanym obiektowo. To jest szablon, od którego zaczynam:

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

Najważniejsze rzeczy do zauważenia to:

  • Nie używam symboli wieloznacznych. importuję pakiet jako "tk", co wymaga prefiksu wszystkich poleceń przez tk.. Zapobiega to zanieczyszczeniu globalnej przestrzeni nazw, a także sprawia, że kod jest całkowicie oczywisty, gdy używasz klas Tkinter, klas ttk lub niektórych własnych.

  • Główne aplikacja jest klasą . Daje to prywatną przestrzeń nazw dla wszystkich wywołań zwrotnych i prywatnych funkcji i ogólnie ułatwia organizowanie kodu. W stylu proceduralnym musisz kodować odgórnie, definiować funkcje przed ich użyciem itp. Dzięki tej metodzie nie robisz tego, ponieważ nie tworzysz głównego okna aż do ostatniego kroku. Wolę dziedziczenie z tk.Frame tylko dlatego, że zazwyczaj zaczynam od tworzenia ramki, ale nie jest to wcale konieczne.

Jeśli Twoja aplikacja ma dodatkowe okna toplevel, polecam, aby każda z nich była osobną klasą, dziedziczącą z tk.Toplevel. Daje to wszystkie te same zalety, o których mowa powyżej-okna są atomowe, mają własną przestrzeń nazw, A kod jest dobrze zorganizowany . Dodatkowo ułatwia umieszczenie każdego z nich we własnym module, gdy kod zacznie się powiększać.

Na koniec warto rozważyć użycie klas dla każdej większej części interfejsu. Na przykład, jeśli tworzysz aplikację z paskiem narzędzi, panelem nawigacji, paskiem stanu i obszarem głównym, możesz utworzyć każdą z tych klas. To sprawia, że twój główny kod jest dość mały i łatwy do zrozumienia:

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)

Ponieważ wszystkie te instancje mają wspólny rodzic, rodzic staje się "kontrolerem" architektury model-widok-kontroler. Tak więc, na przykład, główne okno może umieścić coś na pasku stanu przez wywołanie self.parent.statusbar.set("Hello, world"). Pozwala to na zdefiniowanie prostego interfejsu pomiędzy komponentami, co pomaga utrzymać sprzęganie z minimunem.

 161
Author: Bryan Oakley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-29 13:50:03

Umieszczenie każdego okna najwyższego poziomu w osobnej klasie daje ponowne użycie kodu i lepszą organizację kodu. Wszystkie przyciski i odpowiednie metody obecne w oknie powinny być zdefiniowane wewnątrz tej klasy. Oto przykład (zaczerpnięty z Tutaj):

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

Zobacz też:

Mam nadzieję, że to pomoże.
 27
Author: alecxe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:29

Oto doskonały samouczek na temat projektowania graficznego tkinter, z kilkoma przykładami -- http://python-textbok.readthedocs.org/en/latest/Introduction_to_GUI_Programming.html

Oto kolejny przykład z wzorcem projektowym MVC -- https://sukhbinder.wordpress.com/2014/12/25/an-example-of-model-view-controller-design-pattern-with-tkinter-python/

 6
Author: NargothBond,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-18 18:39:34

To nie jest zła struktura; będzie działać dobrze. Jednak musisz mieć funkcje w funkcji, aby wykonywać polecenia, Gdy ktoś kliknie przycisk lub coś

Więc co można zrobić, to napisać klasy dla tych, a następnie mają metody w klasie, które obsługują polecenia dla kliknięć przycisków i takie.

Oto przykład:

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

Zwykle programy tk z wieloma oknami to wiele dużych klas i w __init__ tworzone są wszystkie wpisy, etykiety itp., a następnie każda metoda obsługuje zdarzenia kliknięcia przycisku

Tak naprawdę nie ma właściwego sposobu, aby to zrobić, cokolwiek działa dla Ciebie i wykonuje zadanie tak długo, jak jest czytelne i możesz łatwo to wyjaśnić, ponieważ jeśli nie możesz łatwo wyjaśnić swojego programu, prawdopodobnie jest lepszy sposób, aby to zrobić.

Spójrz na myślenie w Tkinter.

 3
Author: Serial,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-25 16:13:53

OOP powinno być podejściem, a frame powinno być zmienną klasy zamiast zmiennej instancji .

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

Tutaj wpisz opis obrazka

Numer referencyjny: http://www.python-course.eu/tkinter_buttons.php

 1
Author: Nik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-17 01:52:36

Prawdopodobnie najlepszym sposobem nauczenia się struktury programu jest czytanie kodu innych osób, zwłaszcza jeśli jest to duży program, do którego wiele osób wniosło swój wkład. Po przyjrzeniu się kodowi wielu projektów, powinieneś zorientować się, jaki powinien być styl konsensusu.

Python, jako język, jest wyjątkowy, ponieważ istnieją pewne silne wytyczne, jak sformatować kod. Pierwszy to tzw. "Zen Pythona":

    Piękne jest lepsze niż brzydki.
  • Explicit jest lepszy niż implicit.
  • proste jest lepsze niż złożone.
  • Kompleks jest lepszy niż skomplikowany.
  • Płaskie jest lepsze niż zagnieżdżone.
  • Sparse jest lepsze niż gęste.
  • liczy się czytelność.
  • specjalne przypadki nie są wystarczająco specjalne, aby złamać zasady.
  • Chociaż praktyczność bije czystość.
  • błędy nigdy nie powinny mijać po cichu.
  • chyba, że wyraźnie wyciszono.
  • W obliczu dwuznaczność, Odrzuć pokusę zgadywania.
  • Powinien być jeden, a najlepiej tylko jeden, oczywisty sposób. Chociaż ten sposób może nie być oczywisty na początku, chyba że jesteś Holendrem. Teraz jest lepiej niż nigdy.
  • chociaż nigdy nie jest często lepiej niż prawo teraz.
  • jeśli implementacja jest trudna do wyjaśnienia, to zły pomysł.
  • jeśli implementacja jest łatwa do wyjaśnienia, może to być dobry pomysł.
  • Przestrzenie nazw są jedną świetny pomysł. zróbmy więcej takich!

Na bardziej praktycznym poziomie znajduje się PEP8 , przewodnik po stylach dla Pythona.

Mając to na uwadze, powiedziałbym, że Twój styl kodu nie pasuje, szczególnie do zagnieżdżonych funkcji. Znajdź sposób, aby je spłaścić, używając klas lub przenosząc je do oddzielnych modułów. Dzięki temu struktura Twojego programu będzie znacznie łatwiejsza do zrozumienia.

 0
Author: Inbar Rose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-04 09:46:05

Ja osobiście nie używam podejścia zorientowanego na sprzeciw, głównie dlatego, że a) tylko przeszkadza; b) nigdy nie wykorzystasz tego jako modułu.

Ale coś, co nie jest tutaj omawiane, to to, że Musisz używać wątków lub przetwarzania wieloprocesorowego. Zawsze. w przeciwnym razie Twoja aplikacja będzie okropna.

Po prostu wykonaj prosty test: Uruchom okno, a następnie pobierz jakiś adres URL lub cokolwiek innego. zmiany oznaczają, że interfejs użytkownika nie będzie aktualizowany podczas żądania sieciowego. Oznacza to, że okno aplikacji zostanie złamane. zależy od systemu operacyjnego, na którym się znajdujesz, ale najczęściej nie będzie przerysowywany, wszystko, co przeciągniesz przez okno, będzie na nim tynkowane, dopóki proces nie wróci do mainloop TK.

 -5
Author: gcb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-07 19:13:43