2014-02-28 129 views
1

我有一個Tkinter的GUI腳本,我很滿意,但有一個例外:我的框架似乎在運行時移動,取決於文本的大小顯示在其中一個框架中。它從這個:Tkinter:移動的框架(?)

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

有沒有人知道爲什麼會發生這種情況?提前致謝!

回答

3

由於網格佈局管理器根據包含的小部件的大小確定行的大小,列數。

指定minsize,weight(使用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() 
    
+0

謝謝,就是這樣! – Sajber

2

看起來是因爲你的佈局是由內容決定的。您可以嘗試鎖定控件的大小以避免這種情況。

例如,請注意設置「​​選項」信息時您的框架如何移動。正是這種東西導致你的控件重新分配。

+1

好的,我該怎麼做? – Sajber