Возникли проблемы с Tkinter, использующим ООП

avatar
owwix
8 августа 2021 в 19:03
81
1
0

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

import tkinter as tk
from tkinter import ttk as ttk
import sqlite3

class Button(tk.Frame):
    def __init__(self):
        tk.Frame.__init__(self)
        tk.Button(root, text = "Hello", width = 25)

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.button = Button()
        
        self.button.pack(side="bottom",fill="x")

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root).pack(side="top", fill="both", expand=True)
    root.mainloop()
Источник
quamrana
8 августа 2021 в 19:06
0

Пожалуйста, обновите свой вопрос вопросом.

TheLizzard
8 августа 2021 в 19:06
2

Класс Button не должен полагаться на глобальную переменную root. Также вы должны вызвать .pack/.grid/.place внутри класса Button на tk.Button

TheLizzard
8 августа 2021 в 19:06
0

@quamrana Судя по коду, кнопка не появится на экране.

quamrana
8 августа 2021 в 19:08
1

Что ж, мы можем знать, просто взглянув на то, что на самом деле делает код, но OP может иметь другое определение having difficulty with tkinter.

owwix
8 августа 2021 в 19:13
0

@TheLizzard Спасибо! Когда вы говорите, что класс Button не должен полагаться на корневую переменную, что вы имеете в виду? Разве мне не нужно передавать родительское окно в качестве аргумента для Button()? или я передаю его в качестве аргумента моему классу кнопок. Где бы я создал кнопку как таковую: self.button = Button(root)

TheLizzard
8 августа 2021 в 19:19
1

@owwix ваш класс MainApplication также не должен полагаться на глобальную переменную root. Вместо этого вы должны передать self как: self.button = Button(self). Я напишу ответ.

Ответы (1)

avatar
TheLizzard
8 августа 2021 в 19:25
1

Попробуйте это:

import tkinter as tk
from tkinter import ttk # The `as tkk` isn't needed


# Here you might want to consider inheriting from `tk.Button` but it isn't going to change anything
class Button(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        # It's always a good idea to keep a reference to all of your widgets
        self.button = tk.Button(self, text="Hello", width=25)
        # You should call `.pack`/`.grid`/`.place` here:
        # Note it doesn't really matter which one you choose
        self.button.pack(fill="both")

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent # Technically this isn't needed because the line above sets `self.master` to parent

        self.button = Button(self) # Pass in self into the Button class
        self.button.pack(side="bottom", fill="x")


if __name__ == "__main__":
    root = tk.Tk()
    main_app = MainApplication(root)
    main_app.pack(side="top", fill="both", expand=True)
    root.mainloop()

Я передал self при создании объекта Button в self.button = Button() и вызвал self.button.pack(...) внутри класса Button.

Весь смысл ООП-программирования в том, чтобы ограничить глобальные переменные и сгруппировать похожие объекты в одном определении класса. Вот почему ваши классы Button и MainApplication не должны полагаться на root. Кроме того, ваш код очень хорош: D

owwix
8 августа 2021 в 19:41
0

Большое спасибо! Хотя мне нужно некоторое разъяснение. Вы сказали отметить, что «на самом деле не имеет значения, какой из них вы выберете». Вы имеете в виду, что не имеет значения, выберу ли я его упаковать, разместить на сетке или разместить? Или что не имеет значения, вызываю ли я .pack/.grid/.place в классе Button или в классе MainApplication? Потому что я заметил, что вы упаковали кнопку в оба класса, что меня немного сбивает с толку.

TheLizzard
8 августа 2021 в 19:45
0

Не имеет значения, использовали ли вы pack/grid/place внутри класса Button в tk.Button. Обычно я предпочитаю использовать pack, потому что так легче заставить виджеты расширяться. Это просто личное предпочтение.

owwix
8 августа 2021 в 19:55
0

Я понимаю. Есть ли причина, по которой вы упаковали кнопку дважды?

TheLizzard
8 августа 2021 в 19:58
0

@owwix Я упаковал его только один раз. Не забывайте, что в self.button = Button(self) self.button на самом деле принадлежит классу Button. Так что это tk.Frame, а не tk.Button. Посмотрите на class Button(tk.Frame). Это заставляет класс Button наследовать от tk.Frame, поэтому в глазах tkinter это рамка, а не кнопка.

TheLizzard
8 августа 2021 в 20:00
0

@owwix Также я сделал ошибку, исправив свой ответ. Я только что заметил, что забыл изменить tk.Button(root, text="Hello", width=25) => tk.Button(self, text="Hello", width=25)

owwix
8 августа 2021 в 20:10
0

Итак, в классе Button вы упаковываете кнопку во фрейм, а затем в классе MainApplication вы упаковываете фрейм в корневое окно?

owwix
8 августа 2021 в 20:14
0

Давайте продолжим обсуждение в чате.

TheLizzard
8 августа 2021 в 20:15
0

@owwix Вот именно.