[英]Tkinter: frames (?) moving around
I've got a little Tkinter GUI script which I'm kind of happy with, with one exception: my frames seem to move about during the runtime, depending on the size of text being shown in one of the frames. 我有一个Tkinter GUI脚本,我很满意,但有一个例外:我的框架在运行时似乎在移动,这取决于其中一个框架中显示的文本大小。 It goes from this:
它来自于:
... to this: ...对此:
... and this: ... 和这个:
... depending on the selection in the listbox, ie the amount of text being shown in info_message
. ...取决于列表框中的选择,即
info_message
中显示的文本量。 This is my code: 这是我的代码:
# -*- coding: iso-8859-1 -*-
""" Layout
dice_frame (1,1) list_frame(1,2) info_frame (1,3)
ref_frame (2,1-3)
"""
from tkinter import *
import random
import pandas as pd
root = Tk()
root.wm_title("RP")
root.geometry('500x503')
root.resizable(0, 0)
# ----------------------------------- Dice ------------------------------------
def dice_1():
""" 2d6 generator without modifiers """
dice_result = random.randrange(1, 6) + random.randrange(1, 6)
dice_main.config(text=dice_result)
def dice_2(widget_1, widget_2):
""" Creature 2d6 dice with skill modifier """
dice_result = random.randrange(1, 6) + random.randrange(1, 6)
text = widget_2.cget('text')
if text != '±0':
modifier = int(text)
else:
modifier = 0
widget_1.config(text=dice_result + modifier)
# Dice widgets
dice_frame = Frame(root, bd=5)
dice_frame.grid(row=1, column=1)
dice_label = Label(dice_frame, text='Dice', justify=CENTER)
dice_label.pack()
dice_main = Button(dice_frame, text='2d6', command=dice_1, height=2, width=2,
font=('TkDefaultFont', 10))
dice_main.pack()
# ------------------------------- List & Info ---------------------------------
# Read stats and personalities from file
all_stats = pd.read_excel('Enemies.xlsx', sheetname='Sheet1', sep=';',
keep_default_na=False, encoding='iso-8859-1')
all_traits = pd.read_excel('NPC Traits.xlsx', sheetname='Sheet1', sep=';')
# Create and fill listbox
list_frame = Frame(root, bd=5)
list_frame.grid(row=1, column=2)
list_label = Label(list_frame, text='Enemies', font=('TkFixedFont', 12))
list_label.grid(row=1, column=1)
listbox1 = Listbox(list_frame, height=10, width=20)
for n in range(len(all_stats)):
listbox1.insert(n+1, all_stats.iloc[n][0])
listbox1.grid(row=2, column=1, pady=5)
# Info box for listbox selection
info_message = Message(root, width=300)
info_message.grid(row=1, column=3)
def list_selection(event):
""" Gets selection and info/stats for info_message """
index = int(listbox1.curselection()[0])
stats = all_stats.iloc[index]
info_text = str(stats[0]) + '\n' # just the name
for m in range(int((len(stats)-2)/2)): # rest of the stats
info_text += ('\n' + str(stats[4 + m*2]) + '\t' + str(stats[3 + m*2]))
info_message.config(text=info_text)
listbox1.bind('<ButtonRelease-1>', list_selection)
# -------------------------------- Load Stats ---------------------------------
def reduce(widget_1, widget_2):
""" Function for reducing the value of a skill by 2 """
# Gets current value
text = widget_1.cget('text')
if text == '±0':
value = 0
else:
value = int(text)
value += -2
# Sets new value based on previous value
if value > 0:
widget_1.config(text='+' + str(value))
elif value == 0:
widget_1.config(text='±0')
elif value == -2:
widget_1.config(text='-2')
elif value < -2:
widget_1.config(text='X ', state=DISABLED, relief=SUNKEN,
disabledforeground='red')
if widget_2 != '':
widget_2.config(text='', state=DISABLED, relief=FLAT)
def generate_traits():
""" Generates a random personality for a creature """
t1 = all_traits.iloc[random.randrange(1, 10)][random.randrange(1, 10)]
t2 = all_traits.iloc[random.randrange(1, 10)][random.randrange(1, 10)]
t3 = all_traits.iloc[random.randrange(1, 10)][random.randrange(1, 10)]
return [t1, t2, t3]
def load():
""" Function for loading a creature's stats into a new window """
# Create a new window
top = Toplevel(bd=10)
top.resizable(0, 0)
# Stats based on listbox selection
index = int(listbox1.curselection()[0])
stats = all_stats.iloc[index]
# Name
name = Label(top, text=stats[0], font=('TkDefaultFont', 12))
name.grid(row=1, column=1, columnspan=3)
# Separator line 1
separator_1 = Canvas(top, height=15, width=300)
separator_1.grid(row=2, column=1, columnspan=3)
separator_1.create_line(10, 7.5, 290, 7.5)
# Creates arbitrary number of modifier buttons, labels and associated dice
modifiers = dict()
skills = dict()
dice = dict()
for k in range(int((len(stats) - 4)/2)):
if stats[k*2 + 3] != '':
modifiers[k] = Button(top, text=stats[4 + k*2], command=lambda a=k:
reduce(modifiers[a], dice[a]), width=1)
skills[k] = Label(top, text=stats[3 + k*2], justify=CENTER)
dice[k] = Button(top, width=1, text='Roll', command=lambda a=k:
dice_2(dice[a], modifiers[a]))
modifiers[k].grid(row=k+3, column=1)
skills[k].grid(row=k+3, column=2)
dice[k].grid(row=k+3, column=3)
# Skill padding
padding_row = len(modifiers) + 4
padding_button = Button(top, width=1, text=stats[1])
padding_button.config(command=lambda: reduce(padding_button, ''))
padding_button.grid(row=padding_row, column=1)
padding_label = Label(top, text='Padding', justify=CENTER)
padding_label.grid(row=padding_row, column=2)
# Personality
if stats[2]:
# Separator line 2
separator_2 = Canvas(top, height=15, width=300)
separator_2.grid(row=padding_row + 1, column=1, columnspan=3)
separator_2.create_line(10, 7.5, 290, 7.5)
# Generate three random personality traits
traits = generate_traits()
trait_1 = Label(top, text=traits[0], justify=CENTER)
trait_1.grid(row=padding_row + 2, column=1)
trait_2 = Label(top, text=traits[1], justify=CENTER)
trait_2.grid(row=padding_row + 2, column=2)
trait_3 = Label(top, text=traits[2], justify=CENTER)
trait_3.grid(row=padding_row + 2, column=3)
# Button for loading a creature
load_button = Button(list_frame, text='Load', command=load)
load_button.grid(row=3, column=1, pady=5)
# ----------------------------- Reference sheet -------------------------------
ref_frame = Frame(root)
ref_frame.grid(row=3, column=1, columnspan=3, sticky=W)
image = PhotoImage(file='PDQ Table.gif')
ref_table = Label(ref_frame, image=image)
ref_table.pack()
root.mainloop()
Does anybody know why this is happening? 有人知道为什么会这样吗? Thanks in advance!
提前致谢!
Because grid layout manager determines the sizes of rows, columns according to the sizes of contained widgets. 由于网格布局管理器确定行,列的大小,因此要根据所包含窗口小部件的大小。
Specifying minsize
, weight
(by using grid_columnconfigure
) could help you solve your issue. 指定
minsize
, weight
(通过使用grid_columnconfigure
)可以帮助您解决问题。
For example, try following examples (with or without grid_columnconfigure
): 例如,尝试以下示例(带有或不
grid_columnconfigure
):
Specifying minsize
: 指定
minsize
:
root = Tk() root.geometry('500x503') def make_button_wider(): b['text'] += '++++++' Label(root, text='Dice', justify=CENTER).grid(row=1, column=1) Listbox(root).grid(row=1, column=2) b = Button(root, text='make it wider', command=make_button_wider) b.grid(row=1, column=3) Label(root, text='a'*70).grid(row=3, column=1, columnspan=3) root.grid_columnconfigure(1, minsize=200) # <<< root.grid_columnconfigure(2, minsize=200) # <<< root.mainloop()
Specifying weight
: 指定
weight
:
root = Tk() root.geometry('500x503') def make_button_wider(): b['text'] += '++++++' Label(root, text='Dice', justify=CENTER).grid(row=1, column=1) Listbox(root).grid(row=1, column=2) b = Button(root, text='make it wider', command=make_button_wider) b.grid(row=1, column=3) Label(root, text='a'*70).grid(row=3, column=1, columnspan=3) root.grid_columnconfigure(1, weight=0) # <<< root.grid_columnconfigure(2, weight=0) # <<< root.grid_columnconfigure(3, weight=1) # <<< root.mainloop()
It looks like it's because your layout is being determined by the content. 看起来是因为您的布局由内容决定。 You could try locking the sizes of your controls to avoid this.
您可以尝试锁定控件的大小以避免这种情况。
For instance, note how your frame is moving when the "Option" information is set. 例如,请注意设置“选项”信息时框架如何移动。 It's this sort of stuff that's causing your controls to get re-allocated.
正是这种情况导致您的控件被重新分配。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.