简体   繁体   English

Tkinter:四处移动的帧(?)

[英]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. 指定minsizeweight (通过使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM