Как разместить кнопки бок о бок в tkinter, используя метод размещения?

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

MWE

Как сделать расстояние между кнопками одинаковым?

%%writefile a.py
import sys
import tkinter as tk
from tkinter import ttk,messagebox

win = tk.Tk()

def countdown(win):
    child = tk.Toplevel(win)
    child.geometry('400x300')
    child.resizable(0, 0)
    
    # label: current time title
    tk.Label(child, font='arial 15 bold', text='current time :').place(x=40, y=70)
    tk.Label(child, font='arial 15 bold', text='set the time').place(x=40, y=150)
    tk.Label(child,text='',fg='gray25').place(x=190, y=70)

    frame_top = tk.Frame(child)
    frame_top.pack(expand=False, fill=tk.X)
    
    frame_bottom = tk.Frame(child)
    frame_bottom.pack(expand=False, fill=tk.X)

    mins = [1,2,5,10,15,20,25,30,35,40]
    for i,minn in enumerate(mins):
        tk.Button(frame_top,text=str(minn)+'m',bd='5',).pack(expand=True, side=tk.LEFT)

    for i,minn in enumerate([45,50,55,60,90,120,150,180]):
        tk.Button(frame_bottom,text=str(minn)+'m',bd='5',).pack(expand=True, side=tk.LEFT)

menubar = tk.Menu(win)
menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label = "Scripts", menu=menu)

menu.add_command(label='Countdown',command=lambda : countdown(win))
menu.add_command(label='Exit',command=sys.exit)

win.config(menu=menubar)
win.mainloop()

Предположение

.place() на самом деле не лучший инструмент для этой работы. Научитесь использовать .pack() или .grid(), они делают гораздо больше работы за вас.
jasonharper 23.11.2022 20:17
place — самый сложный способ выполнить эту задачу. Почему вы хотите использовать place?
Bryan Oakley 23.11.2022 20:18

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

dallascow 23.11.2022 20:21

Я слышал, что .grid не работает для дочернего окна" - это совершенно неверная информация. Все менеджеры геометрии работают во всех типах виджетов.

Bryan Oakley 23.11.2022 20:29
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вам будет намного проще использовать другой менеджер геометрии, такой как pack() или, что еще лучше, grid()

Использование pack:

import tkinter as tk

child = tk.Tk()
child.geometry('400x300')

x,w = 0,40
mins = [1,2,5,10,15,20,25,30,35,40]
mins2 = [45,50,55,60,90,120,150,180]
# create some frames to contain each row of buttons
frame_top = tk.Frame(child)
frame_top.pack(expand=False, fill=tk.X)
frame_bottom = tk.Frame(child)
frame_bottom.pack(expand=False, fill=tk.X)

for minn in (mins):
    button = tk.Button(frame_top, text=str(minn)+'m', bd='5')
    button.pack(expand=True, side=tk.LEFT)

for minn in (mins2):
    button = tk.Button(frame_bottom, text=str(minn)+'m', bd='5')
    button.pack(expand=True, side=tk.LEFT)

child.mainloop()

Использование grid:

import tkinter as tk

child = tk.Tk()
child.geometry('400x300')

x,w = 0,40
mins = [1,2,5,10,15,20,25,30,35,40]
mins2 = [45,50,55,60,90,120,150,180]

for i, min in enumerate(mins):
    button = tk.Button(child, text=str(minn)+'m', bd='5')
    button.grid(row=0, column=i)

for i, minn in enumerate(mins2):
    button = Button(child, text=str(minn)+'m', bd='5')
    button.grid(row=1, column=i)

child.mainloop()

По общему признанию, я лучше всех знаком с pack() — если кто-то увидит проблему с моей реализацией grid(), обязательно дайте мне знать!


Приложение

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

# DON'T:
button = ttk.Button(parent).pack()
# button = None
# DO:
button = ttk.Button(parent)  # instantiate widget
button.pack()  # pack separately
# button = .!button

Причина объясняется здесь, но суть в том, что методы менеджера геометрии возвращают None, и это может вызвать проблемы, если вы не обращаете внимания.

Это здорово, это также работает для моего обновленного вопроса?

dallascow 23.11.2022 20:28

Должен, да - основная идея та же самая

JRiggles 23.11.2022 20:31

Я заменил .place на .pack(expand=True, side=tk.LEFT) и получил вывод, как показано в обновленном вопросе. Как управлять этим в два ряда?

dallascow 23.11.2022 20:38

Если вы используете pack(), вам нужно создать несколько Frame, которые будут действовать как контейнеры для каждого ряда кнопок, как я описал в своем первом примере.

JRiggles 23.11.2022 20:40

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