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

class GUI:
    def __init__(self, window):
        self.window = window
        self.window.title("RPG")
        self.window.geometry("600x400")
        self.window.configure(bg="black")
        self.window.grid_anchor(anchor=CENTER)

        self.header = Frame(self.window, bg="green", height=25, width=600)
        self.frame = Frame(self.window, bg="red", height=375, width=600)

        self.header.grid(row=0)
        self.frame.grid(row=1)

        self.label1 = Label(self.header, text="Hello World", bg="black", fg="white")
        self.label2 = Label(self.frame, text="This is the Game")

        self.label1.grid(row=0, column=0)
        self.label2.grid(row=0, column=0)


root = Tk()
gui = GUI(root)
root.mainloop()

Я хотел бы отобразить оба кадра, так же, как и цветовые блоки, и иметь центрированную метку в каждом, но она вообще не отображает рамки, только метки.

0
josephholten 19 Авг 2019 в 02:17

2 ответа

Лучший ответ

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

Кроме того, вы используете grid, а grid создаст наименьшие возможные строки и столбцы, чтобы соответствовать тому, что находится в строке и столбце. grid использует только столько места, сколько необходимо, и не будет использовать дополнительное пространство, если вы не настроили его для этого. Кроме того, сетка будет центрировать элементы в выделенном пространстве, поэтому даже если столбец или строка больше, чем элемент, элемент не заполнит эту строку или столбец.

Поначалу это может показаться нелогичным, но на самом деле эти правила работают довольно хорошо, когда вы понимаете, как grid работает.

Предполагая, что вы хотите, чтобы header и frame заполнили окно, вам необходимо настроить grid, чтобы знать, что делать с дополнительным доступным пространством. Это делается путем присвоения строке или столбцу «веса».

Например, предполагая, что вы хотите, чтобы self.header был горизонтальным условием в верхней части, а self.frame занимал все дополнительное пространство, необходимо добавить следующий оператор:

self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)

С нулевой строкой, имеющей вес по умолчанию 0 (ноль), grid предоставит все дополнительное вертикальное пространство self.frame. Установив вес 1 (один) в нулевой столбец, этот столбец получит все дополнительное горизонтальное пространство.

При этом для фрейма будет выделено достаточно места сверху для заголовка, а все дополнительное пространство будет выделено для self.frame. Есть еще один шаг, который нужно сделать.

Несмотря на то, что self.frame предоставлено все дополнительное пространство, вы должны указать grid растянуть рамку, чтобы она занимала все выделенное пространство. Вы делаете это с помощью опции sticky. Он принимает буквы, представляющие точки на компасе: n (север), s (юг), e (восток) и w (запад). Чтобы кадр занимал все выделенное пространство, нужно, чтобы он «прилипал» ко всем четырем сторонам:

self.frame.grid(row=1, column=0, sticky="nsew")

Точно так же, чтобы растянуть заголовок и заполнить его по горизонтали, можно сказать, что он «прилипает» к востоку и западу:

self.header.grid(row=0, column=0, sticky="ew")

При этом зеленая рамка заголовка заполнит верхнюю часть экрана, а красная рамка заполнит все остальное пространство.

screenshot

Это, вероятно, все еще не совсем то, что вы хотите, но проблема идентична. Если вы хотите, чтобы метка была распределена по всему пространству в заголовке, вы должны использовать для веса строки и столбца 0. Делая это, вы центрируете метку. Если вы хотите, чтобы метка занимала разрешенное пространство, используйте sticky.

Аналогично, если вы хотите, чтобы все остальные метки заполняли нижнюю рамку, присвойте этой строке и столбцу вес, и метка будет центрирована в пространстве. Если вы хотите, чтобы он занимал все выделенное пространство, используйте sticky.

Например:

    self.header.grid_rowconfigure(0, weight=1)
    self.header.grid_columnconfigure(0, weight=1)

    self.frame.grid_rowconfigure(0, weight=1)
    self.frame.grid_columnconfigure(0, weight=1)

screenshot

1
Bryan Oakley 19 Авг 2019 в 22:09

Граница по умолчанию для Frame равна 0, что означает отсутствие границы. Если вы хотите один, то укажите значение больше нуля. Например, обратите внимание на добавленные аргументы ключевого слова bd=1 (вы также можете использовать borderwidth=1):

Кроме того, если вы хотите, чтобы текст центрировался в надписях, вы должны дать им минимум width (количество символов) и указать, как вы хотите, чтобы текст выравнивался в этом пространстве с помощью anchor вариант.

import tkinter as tk


class GUI:
    def __init__(self, window):
        self.window = window
        self.window.title("RPG")
        self.window.geometry("600x400")
        self.window.configure(bg="black")
        self.window.grid_anchor(anchor="center")

        self.header = tk.Frame(self.window, bg="green", height=25, width=600, bd=1)
        self.frame = tk.Frame(self.window, bg="red", height=375, width=600, bd=1)

        self.header.grid(row=0)
        self.frame.grid(row=1)

        self.label1 = tk.Label(self.header, text="Hello World", bg="black", fg="white",
                      width=15, anchor='center')  # ADDED
        self.label2 = tk.Label(self.frame, text="This is the Game",
                      width=15, anchor='center')  # ADDED

        self.label1.grid(row=0, column=0)
        self.label2.grid(row=0, column=0)


root = tk.Tk()
gui = GUI(root)
root.mainloop()

Результат : Снимок экрана, показывающий результат

0
martineau 19 Авг 2019 в 20:38