Tkinter OOP для одного окна с несколькими подфреймами

Я написал графический интерфейс на Tkinter с множеством виджетов. Графический интерфейс работает, но из-за такого количества переменных он довольно запутан. Поэтому я подумал и исследовал, не проще ли поместить подкадры в подклассы.

В принципе мой графический интерфейс устроен следующим образом: Tkinter OOP для одного окна с несколькими подфреймами

Похожий вопрос задан здесь (Ссылка), но ответы больше направлены на структурирование графического интерфейса с помощью виджетов, а не sections. Вот почему я не уверен, что нахожусь на правильном пути. Я протестировал его с помощью следующего кода, но уже столкнулся с загадочными проблемами:

import tkinter as tk
from tkinter import ttk

class main_window(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        # Adding a title to the window
        #self.wm_title("LiL-SimReg")
        self.geometry("800x1000")
        self.title(" xxx ")
        
        INPUTframe(self)
        
class INPUTframe(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        tk.Frame(self, width=800, height=150).place(x=0,y=0)

        
        label10 = tk.Label(self, text = "xxx", font=('Arial',12)).place(x=10,y=0)
        label1 = tk.Label(self, text = "xxx", font=('Arial',10)).place(x=30, y=30)
        button1 = tk.Button(self, text='xxx').place(x=100,y=30)#,command = lambda: path(1))
        textentry1=tk.StringVar()
        entry1 = tk.Entry (self, textvariable=textentry1).place(x=160,y=30,width = "350")
        label11 = tk.Label(self, text = "xxx", font=('Arial',10)).place(x=500,y=30)


        label2 = tk.Label(self, text = "xxx", font=('Arial',10)).place(x=30,y=60)
        button2 = tk.Button(self, text='xxx').place(x=100,y=60)#,command = lambda: path(2))
        textentry2=tk.StringVar()
        entry2 = tk.Entry (self, textvariable=textentry2).place(x=160,y=63,width = "350")
        label21 = tk.Label(self, text = "xxx", font=('Arial',10)).place(x=500,y=60)
        textentry21=tk.DoubleVar(value='x')
        entry21 = tk.Entry (self, textvariable=textentry21).place(x=580,y=63,width = "30")

        label3 = tk.Label(self, text = "xxx", font=('Arial',10)).place(x=30,y=90)
        button3 = tk.Button(self, text='xxx').place(x=100,y=90)#,command = lambda: path(3))
        textentry3=tk.StringVar()
        entry3 = tk.Entry (self, textvariable=textentry3).place(x=160,y=93,width = "350")
        label31 = tk.Label(self, text = "xxx", font=('Arial',10)).place(x=500,y=90)
        textentry31=tk.DoubleVar(value='x')
        entry31 = tk.Entry (self, textvariable=textentry31).place(x=580,y=93,width = "30")
        

if __name__ == "__main__":
    testObj = main_window()
    testObj.mainloop()

Если я использую .place для виджетов, это иногда работает. Лучше это работает с .pack, но тоже не всегда, поэтому кажется, что мой подход неправильный. Ошибки нет, просто ее нет или виджеты отображаются случайным образом.

Не могли бы вы дать мне совет, имеет ли этот подход смысл и в чем ошибка в моем коде?

Почему у тебя tk.Frame(...).place(x=0,y=0)? Он создает рамку и размещает ее, не помещая внутрь никаких виджетов. Также обратите внимание на менеджер геометрии Grid, который может оказаться более полезным с учетом вашей диаграммы.

TheLizzard 25.08.2024 14:52

Привет @TheLizzard, с помощью этой команды я хочу разместить INPUTFRAME.

TMul 25.08.2024 15:05

Используйте self.place(...).

acw1668 25.08.2024 16:42

@acw1668 acw1668 Я уже пробовал self.place(), но он работает не так, как ожидалось. Куда именно мне нужно это поставить?

TMul 25.08.2024 17:57

@ Брайан Окли Я нахожу твое имя во многих вопросах по этому поводу. Знаете, почему это не так хорошо работает с местом?

TMul 25.08.2024 20:14

Добавьте текст к изображению структуры графического интерфейса, неясно, где должна располагаться каждая метка/запись/кнопка. Я не знаю, как это должно выглядеть.

8349697 25.08.2024 23:58

Используйте self.place(...), чтобы заменить строку tk.Frame(...).place(...).

acw1668 26.08.2024 00:42
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
7
114
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Чтобы позиционировать INPUTframe, вам необходимо обновить его __init__.

class INPUTframe(tk.Frame):
    def __init__(self, parent, width=800, height=150):
        tk.Frame.__init__(self, parent, width=width, height=height)
        self.place(x=0, y=0)

        label10 = tk.Label(self, text = "xxx", font=('Arial',12)).place(x=10,y=0)
...

Вы также можете структурировать свое приложение, как в этом примере (один класс).

8349697 25.08.2024 23:29

Если вы хотите разместить фрейм внутри функции __init__(), вам не следует вызывать:

tk.Frame(self, width=800, height=150).place(x=0,y=0)

потому что вместо этого будет создан другой кадр.

Вместо этого используйте self.place(x=0, y=0, width=800, height=150).

Однако я бы посоветовал не вызывать функцию макета самим виджетом. Вместо этого родитель несет ответственность за размещение своих дочерних элементов:

...

class main_window(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        # Adding a title to the window
        #self.wm_title("LiL-SimReg")
        self.geometry("800x1000")
        self.title(" xxx ")
        
        frame = INPUTframe(self, width=800, height=150)
        frame.place(x=0, y=0)

class INPUTframe(tk.Frame):
    def __init__(self, parent, **kwargs):
        tk.Frame.__init__(self, parent, **kwargs)

        label10 = tk.Label(self, text = "xxx", font=('Arial',12)).place(x=10,y=0)
        ...

Так выглядит графический интерфейс?

Я использую Python 3.12.5. Если нет, то игнорируйте ваш parent.

Я изменился (self,...)

на (parent, ...) для каждого виджета

В строке 20, label10 = tk.Label(parent, text = "xxx", bg='red', font=('Arial',12)).place(x=30,y=10) #<== change layout.

Скриншот:

большое спасибо. Это работает! Знаете ли вы, почему .place() не сработал? Это функция или это ошибка наследования, которую я допустил? С помощью .grid() и .place() мне удалось заставить его работать, но мне пришлось менять весь макет, поскольку до сих пор я в основном работал с .place().

TMul 26.08.2024 22:41

Рад, что смог помочь.

toyota Supra 26.08.2024 22:44

Макет Place() выполняет вашу работу. Есть так много способов сделать это.

toyota Supra 27.08.2024 02:25

Прежде всего, когда вы объявляете виджет как переменную, вы не можете добавлять к нему pack/place. вместо,

widget = Widget_type(parent_widget)
widget.pack() # or place

Также следует упомянуть функцию, которая запускается виджетом, следующим образом.

btn = Button(parent_widget, command = function_name) # or lambda function instead of function_name
btn.pack() # or place

Требуемого вами поведения можно легко добиться с помощью пакета. Я предположил, что метка1 и кнопка1 расположены слева, а запись1 и метка11 — справа. Этот комбинированный виджет расположен вторым сверху. (Как я понял из вашего рисунка). Мне не понравилось то место, которое вы разместили методом place.

import tkinter as tk
from tkinter import ttk

class main_window(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        # Adding a title to the window
        #self.wm_title("LiL-SimReg")
        self.geometry("800x1000")
        self.title(" xxx ")
        
        


        top_frame = tk.Frame(self)
        top_frame.pack(side = 'top')
        label10 = tk.Label(top_frame, text = "xxx", font=('Arial',12))
        label10.pack(side = 'top')
        
        second_top = tk.Frame(self)
        second_top.pack(side = 'top', pady=20)
        
        second_top_left = tk.Frame(second_top)
        second_top_left.pack(side= 'left')
        second_top_right = tk.Frame(second_top)
        second_top_right.pack(side= 'right')
        
        # assuming label1 & button1 on left side and entry1 and label11 on right side 
        label1 = tk.Label(second_top_left, text = "xxx", font=('Arial',10))
        label1.pack(side= 'top')
        button1 = tk.Button(second_top_left, text='xxx')
        button1.pack(side = 'top')
        textentry1=tk.StringVar()
        entry1 = tk.Entry (second_top_right, textvariable=textentry1)
        entry1.pack(side='top')
        label11 = tk.Label(second_top_right,  text = "xxx", font=('Arial',10))
        label11.pack(side='top')

        third_top = tk.Frame(self)
        third_top.pack(side='top', pady = 20)
        label2 = tk.Label(third_top, text = "xxx", font=('Arial',10))
        label2.pack(side = 'top')
        button2 = tk.Button(third_top, text='xxx')
        button2.pack(side = 'top')
        textentry2=tk.StringVar()
        entry2 = tk.Entry (third_top, textvariable=textentry2)
        entry2.pack(side = 'top')
        label21 = tk.Label(third_top, text = "xxx", font=('Arial',10))
        label21.pack(side = 'top')
        textentry21=tk.DoubleVar(value='x')
        entry21 = tk.Entry (third_top, textvariable=textentry21)
        entry21.pack(side = 'top')
        
        bottom_frame = tk.Frame(self)
        bottom_frame.pack(side= 'top', pady = 20)

        label3 = tk.Label(bottom_frame, text = "xxx", font=('Arial',10))
        label3.pack(side = 'top')
        button3 = tk.Button(bottom_frame, text='xxx')
        button3.pack(side = 'top')
        textentry3=tk.StringVar()
        entry3 = tk.Entry (bottom_frame, textvariable=textentry3)
        entry3.pack(side = 'top')
        label31 = tk.Label(bottom_frame, text = "xxx", font=('Arial',10))
        label31.pack(side = 'top')
        textentry31=tk.DoubleVar(value='x')
        entry31 = tk.Entry (bottom_frame, textvariable=textentry31)
        entry31.pack(side = 'top')

if __name__ == "__main__":
    testObj = main_window()
    testObj.mainloop()

Другие вопросы по теме