Попытка заточить asp точки размещения фреймов и виджетов в классах для tkinter - PullRequest
0 голосов
/ 13 марта 2020

Как говорится в вопросе, я не могу полностью понять asp смысл использования классов с tkinter.

Я прочитал приличное количество различных сайтов, но продолжаю получать результаты поиска на как создавать и использовать классы, но никто до сих пор не смог дозвониться до меня. Я даже просматривал предложенные вопросы, задавая этот. Наиболее близким к пониманию является объяснение Брайана по этому ответу на вопрос Зачем использовать классы при программировании tkinter gui?

Но все же я чувствую, что я почти там, просто не совсем на грани понимания.

В своем примере, приведенном в ссылке, он создает нетрадиционную программу, а затем лучшую, более традиционную программу это делает то же самое. Я знаю, что он представляет собой гораздо меньший масштаб, чем программы из тысячи строк, которые действительно могут извлечь выгоду из объектно-ориентированного подхода.

Нужно ли, чтобы каждый виджет находился в своем отдельном кадре, который, возможно, является частью еще большего кадра ?

Могут ли классы иметь методы, которые создают и помещают фрейм? Кроме того, могут ли те же классы иметь методы, которые могут создавать, изменять и размещать виджет в ранее созданном фрейме?

У меня также есть некоторый код, который позволяет мне создавать, изменять и размещать виджет. Хотя я знаю, что это не совсем обычное дело, поэтому я был бы очень признателен за этот вклад. Любые предложения о том, что бы вы сделали с этим кодом, чтобы сделать его лучше?

import tkinter as tk

def layout(self, row=0, column=0, columnspan=None, row_weight=None, column_weight=None, color=None, sticky=None, ipadx=None, padx=None, ipady=None, pady=None):
    self.grid(row=row, column=column, columnspan=columnspan, sticky=sticky, ipadx=ipadx, padx=padx, ipady=ipady, pady=pady)
    self.grid_rowconfigure(row, weight=row_weight)
    self.grid_columnconfigure(column, weight=column_weight)
    self.config(bg=color)

class MyLabels(tk.Label):
    def __init__(self, parent, text, **kwargs):
        tk.Label.__init__(self, parent, text=text)
        layout(self, **kwargs)

class MyButtons(tk.Button):
    def __init__(self, parent, text, command, **kwargs):
        tk.Button.__init__(self, parent, text=text, command=command)
        layout(self, **kwargs)


window = tk.Tk()
test_button = MyButtons(window, "hi", None, color="pink")
window.mainloop()

Отредактировано после комментариев: Итак, я работаю много часов со вчерашнего дня, пытаясь воплотить идеи, которые вы имели для меня. Вот то, что я придумал:

import tkinter as tk

window = tk.Tk()

class MyWidgets(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.layout()

    def layout(self):
        self.grid(row=0, column=0)
        self.config(bg="blue")

class MyButtons(MyWidgets):
    def __init__(self, parent, text):
        MyWidgets.__init__(self, parent)
        tk.Button(parent, text=text)
        self.layout()

frme = MyWidgets(window)
btn = MyButtons(frme, text="Test")
window.mainloop()

Я пытался переместить вещи и переписать много областей в этой маленькой побочной программе, и хотя я смог доказать, что btn - фактический доступ атрибут self.config(bg="blue"), кнопка не меняется. На самом деле я не могу найти способ заставить кнопку появиться без необходимости помещать self.grid() в дочерний класс сразу после создания кнопки.

Тем не менее, даже если я действительно добавил self.grid() кнопка все равно не станет синей. Это что-то с self?

Почему кнопка не появляется, когда ее создает дочерний класс, а родительский класс ее размещает?

Примечание: я намеренно опустил весь layout function и заменил его простым config method. Я полагаю, что если я смогу это понять, я смогу найти способ включить всю функцию обратно в код.

1 Ответ

1 голос
/ 13 марта 2020

Должен ли каждый виджет быть в своем отдельном кадре, который, возможно, является частью еще большего кадра?

Это все равно, что спрашивать, нуждается ли каждая часть математического выражения в скобках. Строго говоря, ответ «нет». Однако использование фреймов для организации групп виджетов - это инструмент, предназначенный для облегчения написания и понимания кода, так же как скобки в сложном математическом уравнении облегчают написание и понимание уравнения.

Могут ли классы иметь методы, которые создают и помещают фрейм? Кроме того, могут ли те же классы иметь методы, которые могут создавать, изменять и размещать виджет в ранее созданном фрейме?

Да и да. Методы в классе не имеют никаких ограничений на то, что они могут и не могут делать. Методы класса могут делать все, что может делать нормальная функция.

У меня также есть некоторый код, который позволяет мне создавать, изменять и размещать виджет. Хотя я знаю, что это не совсем обычное дело, поэтому я был бы очень признателен за этот вклад. Любые предложения о том, что бы вы сделали с этим кодом, чтобы сделать его лучше?

«Лучше» очень субъективно. Что лучше для 20 строк кода, может быть не лучше для 200, 2000 или 20000. Что лучше для функции, используемой ровно в два раза, может быть не лучше для функции, используемой сотни или тысячи раз (или наоборот).

При этом вы делаете одну вещь, которая очень нетрадиционна и которая приводит к усложнению понимания вашего кода: вы используете self в качестве параметра для функции, которая не является методом класса. self означает что-то очень специфичное c для python программистов; использование его вне контекста метода очень запутанно.

Вы должны сделать одну из двух вещей для метода layout:

  • Переименуйте self в widget или любой другой термин, отличный от self
  • Создайте базовый класс, который определяет layout, и затем ваши классы наследуются от базового класса. В этом случае self является правильным первым аргументом.

Эта часть ответа относится к коду, который был добавлен после того, как я написал свой оригинальный ответ.

Базовый класс, о котором я говорил, должен быть отдельным классом. Например:

class Base():
    def layout(self):
        self.grid(row=0, column=0)
        self.config(bg="blue")

class MyLabels(Base, tk.Label):
    def __init__(self, parent, text, **kwargs):
        tk.Label.__init__(self, parent, text=text)
        self.layout(self, **kwargs)

class MyButtons(Base, tk.Button):
    def __init__(self, parent, text, command, **kwargs):
        tk.Button.__init__(self, parent, text=text, command=command)
        self.layout(self, **kwargs)

Этот тип класса иногда называют mixin , потому что он не предназначен для создания экземпляра как отдельный объект. Скорее, он «смешивает» некоторое дополнительное поведение с другими классами. Миксины обычно имеют методы, но не имеют собственных __init__.

...