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, но тоже не всегда, поэтому кажется, что мой подход неправильный. Ошибки нет, просто ее нет или виджеты отображаются случайным образом.

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

🤔 А знаете ли вы, что...
Python поддерживает параллельное и асинхронное программирование с помощью модулей asyncio и multiprocessing.


114
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)
...

Если вы хотите разместить фрейм внутри функции __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.

Скриншот:


Прежде всего, когда вы объявляете виджет как переменную, вы не можете добавлять к нему 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()