Лучший способ структурировать приложение tkinter [закрыто]
ниже приведена общая структура моей типичной программы 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()
funAfunB и funC появится еще один Toplevel окна с виджетами, когда пользователь нажимает на кнопки 1, 2, 3.
мне интересно, если это правильный способ написать программу python tkinter? Конечно, это будет работать, даже если я пишу так, но это лучший способ? Это звучит глупо, но когда я вижу коды, написанные другими людьми, их код не перепутан куча функций и в основном у них есть классы.
есть ли какая-то конкретная структура, которой мы должны следовать как хорошей практике? Как я должен планировать, прежде чем начать писать программу python?
Я знаю, что нет такой вещи, как лучшая практика в программировании, и я тоже не прошу об этом. Мне просто нужны некоторые советы и объяснения, чтобы держать меня в правильном направлении, поскольку я изучаю Python самостоятельно.
7 ответов:
Я выступаю за объектно-ориентированный подход. Это шаблон, который я начинаю с:
# 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()важные вещи, чтобы заметить это:
Я не использую импорт подстановочных знаков. я импортирую пакет как "tk", который требует, чтобы я префикс всех команд с
tk.. Это предотвращает загрязнение глобального пространства имен, а также делает код полностью очевидным при использовании классов Tkinter, классов ttk или некоторых из ваших собственных.основное приложение-это класс. Это дает вам частное пространство имен для всех ваших обратных вызовов и частных функций и просто упрощает организацию вашего кода. В процедурном стиле вы должны кодировать сверху вниз, определяя функции перед их использованием и т. д. С помощью этого метода вы этого не сделаете, так как вы фактически не создаете главное окно до самого последнего шага. Я предпочитаю наследовать от
tk.Frameпросто потому, что я обычно начинаю с создания рама, но она ни в коем случае не нужна.если ваше приложение имеет дополнительные окна верхнего уровня, я рекомендую сделать каждый из них отдельным классом, наследуя от
tk.Toplevel. Это дает вам все те же преимущества, упомянутые выше-окна являются атомарными, они имеют свое собственное пространство имен, и код хорошо организован. Кроме того, это позволяет легко поместить каждый в свой собственный модуль, как только код начинает становиться большим.наконец, вы можете рассмотреть возможность использования классы для каждой основной части вашего интерфейса. Например, если вы создаете приложение с панелью инструментов, панелью навигации, строкой состояния и основной областью, вы можете создать каждый из этих классов. Это делает ваш основной код довольно маленьким и простым для понимания:
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)поскольку все эти экземпляры имеют общий родитель, родитель фактически становится частью "контроллера" архитектуры model-view-controller. Так, например, главное окно может разместить что-то на строка состояния по вызову
self.parent.statusbar.set("Hello, world"). Это позволяет вам определить простой интерфейс между компонентами, помогая держать соединение к minimun.
помещение каждого из ваших окон верхнего уровня в свой собственный отдельный класс дает вам повторное использование кода и лучшую организацию кода. Любые кнопки и соответствующие методы, которые присутствуют в окне, должны быть определены внутри этого класса. Вот пример (взято из здесь):
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()Смотрите также:
- простой Привет мир от tkinter docs
- пример кода Tkinter для нескольких окон, почему кнопки не загружаются правильно?
- Tkinter: как Показать / Скрыть окно
надеюсь, что это поможет.
вот отличный учебник по дизайну графического интерфейса tkinter, с несколькими примерами -- http://python-textbok.readthedocs.org/en/latest/Introduction_to_GUI_Programming.html
вот еще один пример с шаблоном проектирования MVC -- https://sukhbinder.wordpress.com/2014/12/25/an-example-of-model-view-controller-design-pattern-with-tkinter-python/
это не плохая структура; она будет работать просто отлично. Однако у вас должны быть функции в функции для выполнения команд, когда кто-то нажимает на кнопку или что-то
Итак, что вы могли бы сделать, это написать классы для них, а затем иметь методы в классе, которые обрабатывают команды для нажатия кнопок и т. д.
вот пример:
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()обычно программы tk с несколькими окнами-это несколько больших классов и в
__init__все записи, метки etc создаются, а затем каждый метод должен обрабатывать события нажатия кнопкина самом деле нет правильного способа сделать это, что бы ни работало для вас и выполняло работу до тех пор, пока оно читается, и вы можете легко объяснить это, потому что если вы не можете легко объяснить свою программу, вероятно, есть лучший способ сделать это.
посмотри думая в Tkinter.
ООП должен быть подход и
frameдолжно быть переменной класс вместо переменная.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()
вероятно, лучший способ узнать, как структурировать вашу программу-это читать код других людей, особенно если это большая программа, в которую внесли свой вклад многие люди. Посмотрев на код многих проектов, вы должны получить представление о том, каким должен быть консенсусный стиль.
Python, как язык, является особенным в том, что есть некоторые сильные рекомендации относительно того, как вы должны форматировать свой код. Первый-это так называемый "Дзен питона":
- красивое лучше, чем уродливое.
- явное лучше, чем неявное.
- простое лучше, чем сложное.
- комплекс лучше, чем сложные.
- плоское лучше, чем вложенное.
- разреженное лучше, чем плотное.
- читабельность имеет значение.
- особые случаи не настолько особые, чтобы нарушать правила.
- хотя практичность бьет чистоты.
- ошибки никогда не проходите молча.
- если явно не замолчать.
- перед лицом двусмысленности откажитесь от соблазна угадать.
- должен быть один-и, желательно, только один-очевидный способ сделать это.
- хотя этот путь не может быть очевидным сначала, если вы не голландец.
- сейчас лучше, чем никогда.
- хотя никогда не бывает лучше, чем право сейчас.
- если реализация трудно объясните, это плохая идея.
- если реализацию легко объяснить, это может быть хорошей идеей.
- пространства имен-это одна отличная идея-давайте сделаем больше из них!
на более практическом уровне, там PEP8, руководство по стилю для Python.
имея это в виду, я бы сказал, что ваш стиль кода на самом деле не подходит, особенно вложенные функции. Найдите способ сгладить их, либо с помощью классы или перемещение их в отдельные модули. Это сделает структуру вашей программы намного проще для понимания.
Я лично не использую объектно-ориентированный подход, в основном потому, что он а) только мешает; б) вы будете никогда использовать в качестве модуля.
но то, что здесь не обсуждается, это то, что вы должны используйте потоковую или многопроцессорную обработку. Всегда. в противном случае ваше приложение будет ужасно.
просто сделайте простой тест: запустите окно, а затем извлеките какой-нибудь URL или что-нибудь еще. изменения ваш пользовательский интерфейс не будет обновляться в то время как сеть запрос происходит. Это означает, что ваше окно приложения будет разбито. зависит от ОС, на которой вы находитесь, но в большинстве случаев он не будет перерисовываться, все, что вы перетаскиваете через окно, будет оштукатурено на нем, пока процесс не вернется к TK mainloop.

Comments