Po co używać klas podczas programowania GUI tkinter w Pythonie


19

Programuję przede wszystkim w Pythonie i zaprogramowałem kilka GUI za pomocą Tkintera, każdy samouczek, jaki kiedykolwiek widziałem, zalecał zdefiniowanie i użycie klasy dla GUI, ale mój GUI działa bezbłędnie przy użyciu tylko procedur, bez klasy.

Dlaczego warto skorzystać z zajęć? Z mojej perspektywy wydaje się po prostu dodatkową warstwą złożoności i niepotrzebnego kodu.

Odpowiedzi:


19

Dlaczego warto skorzystać z zajęć? Ponieważ ułatwia to zadanie, zakładając, że wiesz, jak robić programowanie obiektowe, i zakładasz, że piszesz nietrywialne GUI. Korzystanie z obiektów pozwala łatwo podzielić kod na jednostki modułowe, które są samowystarczalne, a modularyzacja kodu jest ogólnie uważana za najlepszą praktykę.

Programowanie GUI łatwo nadaje się do stylu obiektowego, ponieważ GUI składa się całkowicie z obiektów - etykiet, przycisków, pasków przewijania, obszarów tekstowych itp. Ponieważ już używasz obiektów, porządkowanie kodu w większe obiekty ma sens . Pasek narzędzi jest obiektem, pasek stanu jest obiektem, panel nawigacyjny jest obiektem, główny obszar jest obiektem, każda karta notesu jest obiektem i tak dalej.

Nawet jeśli kod nie jest zbyt skomplikowany, z bardziej praktycznego punktu widzenia pozwala on definiować wiązania i wywołania zwrotne wcześniej w pliku niż definicja funkcji, którą wywołujesz, co moim zdaniem ma sens.

Rozważmy na przykład prosty przykład (przy założeniu, że tkinter został zaimportowany jak import tkinter as tk(python3) lub import Tkinter as tk(python2):

def quit(event=None):
    sys.exit()
root = tk.Tk()
label = tk.Label(root, text="Hello, world")
label.pack()
label.bind("<1>", quit)
root.mainloop()

Dla mnie przepływ tego kodu jest nieprawidłowy. Muszę zdefiniować metodę quit przed odwołaniem się do niej, a tworzenie okna głównego i wywołanie mainloop są oddzielone przez cały inny kod.

Jednak używając klas, mogę napisać kod w bardziej naturalnej kolejności:

class MyWindow(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Hello, world")
        label.pack()
        label.bind("<1>", self.quit)
    def quit(self, event=None):
        sys.exit()

root = tk.Tk()
MyWindow(root).pack()
root.mainloop()

Główna treść GUI znajduje się u góry pliku, a kod pomocniczy znajduje się poniżej. Teraz możesz oczywiście użyć funkcji, aby osiągnąć to samo. Moim zdaniem zajęcia ułatwiają to wszystko.

Kolejną zaletą jest to, że mogę teraz łatwo zmieniać okno zawierające zawartość bez konieczności zmiany czegokolwiek w oknie „głównym” (i odwrotnie). Oznacza to, że mogę dodać ramki lub kompletną nową sekcję do głównego interfejsu GUI, ale nie muszę dotykać ani jednego wiersza kodu w MyWindow. Porównaj to z kodem proceduralnym, w którym może być konieczna zmiana label.pack()instrukcji, oraz instrukcjami pack (lub grid) wszystkich innych widgetów w interfejsie użytkownika.

Wszystko to jednak mówi, że zastosowanie podejścia obiektowego nie jest konieczne do napisania dobrego, czystego, łatwego do utrzymania kodu. To może być, ale może również prowadzić do złego kodu. Pod koniec dnia podejście obiektowe jest tylko narzędziem. To, czy go użyjesz, czy nie, i czy użyjesz go poprawnie, czy nie, zależy od wielu czynników. Może się zdarzyć, że dla Ciebie i dla kodu, który piszesz, funkcjonalny styl jest całkowicie akceptowalny. Myślę, że przekonasz się, że w miarę jak twoje programy stają się bardziej złożone, podejście obiektowe ułatwi uporządkowanie i utrzymanie twojego kodu.


Dlaczego użyłeś ramki w drugim przykładzie? Czy nie możesz tego uniknąć, tak jak w pierwszym przykładzie? Czy kryje się jakaś tajemnica za pomocą Frame z klasami?
multigoodverse 10.04.16

2
Rama jest po prostu dla wygody. Dziedziczenie po Frame nie jest tajemnicą. Mógłbym odziedziczyć objectklasę lub inną klasę, ale zazwyczaj i tak tworzyłem ramkę. Jeśli umieszczam wszystko w ramce, sensowne jest uczynienie klasy ramką. .
Bryan Oakley,

1
Ma sens, dzięki! Widziałem też, jak inni używają self przed zmiennymi, ale widzę, że używasz czegoś podobnego label=tk.Label()zamiast self.tk.Label(). Czy to wybór stylu? Oto przykład z użyciem self: python-textbok.readthedocs.org/en/1.0/…
multigoodverse 10.04.2016

1
@BryanOakley, myślę, że chciałeś użyć rodzica zamiast roota w następującym wierszu MyWindow .__ init__: "label = tk.Label (root, text =" Hello, world ")"
user3885927

1
@ user3885927: tak! Wow, zajęło to prawie trzy lata, aby ktoś to zauważył. Chociaż nie, parentale raczej self, ponieważ sama klasa jest ramą. Dzięki!
Bryan Oakley
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.