Навіщо використовувати класи при програмуванні tkinter gui в python


19

Я програмую в основному на python і запрограмував пару GUI з Tkinter, кожен підручник, який я коли-небудь бачив, рекомендував визначати та використовувати клас для GUI, але мій графічний інтерфейс працює бездоганно, використовуючи лише процедури, без класу.

Навіщо використовувати клас? З моєї точки зору, це просто додатковий рівень складності та непотрібний код.

Відповіді:


19

Навіщо використовувати клас? Оскільки це полегшує роботу, припускаючи, що ви знаєте, як робити об’єктно-орієнтоване програмування, і припускаючи, що ви пишете нетривіальний графічний інтерфейс. Використання об'єктів дозволяє легко розділити код на модульні одиниці, які є автономними, а модуляризація коду, як правило, вважається найкращою практикою.

Програмування графічного інтерфейсу легко піддається об'єктно-орієнтованому стилю, оскільки графічний інтерфейс повністю складається з об'єктів - міток, кнопок, смуг прокрутки, текстових областей тощо. Оскільки ви вже використовуєте об'єкти, упорядкувати код у більші об'єкти має сенс . Панель інструментів - це об'єкт, панель стану - це об'єкт, панель навігації - це об'єкт, основна область - це об'єкт, кожна вкладка ноутбука - це об'єкт тощо.

Навіть коли ваш код не дуже складний, з більш практичної точки зору він дозволяє визначати прив’язки та зворотні дзвінки раніше у файлі, ніж визначення функції, яку ви викликаєте, що, на мою думку, має багато сенсу.

Наприклад, розглянемо простий приклад (якщо припустити, що tkinter був імпортований як import tkinter as tk(python3) або 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()

Для мене потік цього коду - це все неправильно. Я повинен визначити метод виходу, перш ніж посилатись на нього, а створення кореневого вікна та виклик до mainloop відокремлені всіма іншими кодами.

Однак, використовуючи класи, я можу записати код у більш природному порядку:

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

Основна частина GUI знаходиться вгорі файлу, а підтримуючий код - під ним. Тепер, звичайно, ви можете використовувати функції, щоб досягти багато чого одного. На мою думку, хоча, заняття роблять це все трохи легше.

Ще одна перевага полягає в тому, що тепер я можу легко змінити вікно, що містить, не змінюючи нічого про "головне" вікно (і візу навпаки). Тобто я можу додати рамки або новий новий розділ до основного графічного інтерфейсу, але мені не потрібно торкатися жодного рядка коду всередині MyWindow. Порівнюйте це з процедурним кодом, де вам, можливо, доведеться змінити label.pack()оператор і пакет (або сітку) всіх інших віджетів в інтерфейсі.

Однак все, про що говориться, використовуючи об'єктно-орієнтований підхід, не потрібно писати хороший, чистий, ремонтований код. Це може бути, але також може призвести до поганого коду. Зрештою, об'єктно-орієнтований підхід - це лише інструмент. Незалежно від того, використовуєте ви це чи ні, чи правильно ви це використовуєте чи ні, залежить від багатьох факторів. Тож цілком може статися, що для вас і для коду, який ви пишете, функціональний стиль цілком прийнятний. Думаю, ви побачите, що, оскільки ваші програми будуть складнішими, об'єктно-орієнтований підхід полегшить організацію та підтримку вашого коду.


Чому ви використовували Frame у другому прикладі? Чи не могли ви цього уникнути, як ви робили в першому прикладі? Чи є якийсь секрет у використанні Frame з класами?
багатоповерховий

2
Каркас просто для зручності. У наслідування від Frame немає секрету. Я міг успадкувати від objectбудь-якого іншого класу, але, як правило, я все-таки створюю фрейм. Якщо я вкладаю все у рамку, є сенс зробити клас кадром. .
Брайан Оуклі

1
Має сенс, дякую! Також я бачив, як інші використовують self перед змінними, але я бачу, що ви використовуєте щось на зразок label=tk.Label()замість self.tk.Label(). Це вибір стилю? Ось приклад використання self: python-textbok.readthedocs.org/en/1.0/…
multigoodverse

1
@BryanOakley, я думаю, ви мали намір використовувати родитель замість коріння у наступному рядку MyWindow .__ init__: "label = tk.Label (root, text =" Привіт, світ ")"
користувач3885927

1
@ user3885927: так! Ого, минуло майже три роки, щоб хтось це помітив. Хоча, не, parentскоріше self, оскільки сам клас є Frame. Спасибі!
Брайан Оуклі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.