2025, Oct 22 10:01

CTkTabview не растягивается по высоте в customtkinter: что происходит и как исправить

Разбираем баг customtkinter: CTkTabview растягивается, но контент вкладок не заполняет высоту. Минимальный пример и рабочее решение с anchor='s'. Гайд внутри.

CTkTabview не заполняет вертикальное пространство в customtkinter: что происходит и как это исправить

Иногда CTkTabview выглядит так, словно занимает лишь две трети высоты окна, а внизу остается большая пустая область. Grid настроен на растяжение, для sticky указано nsew, но содержимое всё равно не заполняет всю высоту. Разберём минимальный пример, первопричину и рабочее решение.

Минимальный воспроизводимый пример

import customtkinter

class MainWindow(customtkinter.CTk):
    def __init__(self):
        super().__init__()

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

        self.tabs = TabBook(self)
        self.tabs.grid(column=0, row=0, sticky="nsew")

class TabBook(customtkinter.CTkTabview):
    def __init__(self, master):
        super().__init__(master)
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self.add("Tab")

        self.tab("Tab").grid_columnconfigure(0, weight=1)
        self.tab("Tab").grid_rowconfigure(0, weight=1)
        self.tab("Tab").grid(column=0, row=0, sticky="nsew")

Что на самом деле происходит

Похоже, это баг в customtkinter. Сам экземпляр CTkTabview растягивается и заполняет окно, как и ожидается, но внутренняя область содержимого CTkTabview занимает только верхнюю часть виджета. Остальное пространство остаётся неиспользованным. Это легко проверить: поместите внутри вкладки заметный виджет — он будет прижат к верху, а нижняя часть останется пустой.

Как исправить

Инициализируйте CTkTabview с параметром anchor, установленным в "s". С anchor="s" виджет ведёт себя корректно, и содержимое вкладки использует доступное вертикальное пространство как задумано.

import customtkinter

class MainWindow(customtkinter.CTk):
    def __init__(self):
        super().__init__()

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

        self.tabs = TabBook(self)
        self.tabs.grid(column=0, row=0, sticky="nsew")

class TabBook(customtkinter.CTkTabview):
    def __init__(self, master):
        super().__init__(master, anchor='s')
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self.add("Tab")

        self.tab("Tab").grid_columnconfigure(0, weight=1)
        self.tab("Tab").grid_rowconfigure(0, weight=1)
        self.tab("Tab").grid(column=0, row=0, sticky="nsew")

Почему это важно

Когда макет выглядит неправильно, легко заподозрить веса grid, флаги sticky или размеры контейнера. В этом случае всё это уже настроено верно; проблема кроется внутри CTkTabview. Знание того, что сам виджет заполняет родительский контейнер, а его область содержимого — нет, помогает не гоняться за мнимыми ошибками сетки в своём коде.

В репозитории CustomTkinter открыт ишью, отслеживающее это поведение: github.com/TomSchimansky/CustomTkinter/issues/2739

Вывод

Если ваш CTkTabview будто упирается в верхнюю часть окна, оставьте текущие настройки grid и sticky как есть и укажите anchor="s" при создании CTkTabview. Пока апстрим-ошибка не исправлена, эта настройка помогает согласовать содержимое вкладок с доступным пространством и вернуть ожидаемую полноэкранную высоту макета.

Статья основана на вопросе на StackOverflow от frenzy и ответе от J Earls.