Tkinter:框架(?)四处移动

时间:2014-02-28 13:57:07

标签: python python-3.x tkinter

我有一个小Tkinter GUI脚本,我很满意,但有一个例外:我的帧似乎在运行时移动,具体取决于其中一个帧中显示的文本大小。它来自于:

Start

......对此:

Middle

......而且这个:

End

...取决于列表框中的选择,即info_message中显示的文本数量。这是我的代码:

# -*- 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()

有人知道为什么会这样吗?提前谢谢!

2 个答案:

答案 0 :(得分:3)

因为网格布局管理器根据包含的小部件的大小确定行的大小,列。

指定minsizeweight(使用grid_columnconfigure)可以帮助您解决问题。

例如,请尝试以下示例(使用或不使用grid_columnconfigure):

  • 指定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()
    
  • 指定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()
    

答案 1 :(得分:2)

看起来好像是因为你的布局是由内容决定的。您可以尝试锁定控件的大小以避免这种情况。

例如,请注意设置“​​选项”信息时帧的移动方式。正是这种东西导致你的控件被重新分配。