tkinter frame:更改其内容时修复帧高度

时间:2015-02-22 01:02:17

标签: python python-3.x tkinter widget tk

我正在开发一个带有适当GUI的自编模拟工具。通常,有两种主要的用户模式。在第一个中,用户可以输入多个值以进行所需的计算。在所有计算完成后,用户可以切换到"结果模式"点击"显示结果"右下角的按钮。通过这样做,GUI上部带有图像的主窗口不会改变。但是,GUI下部的前一个输入条目应该更改为消息区域,其中显示错误,警告或其他信息(持续时间,收敛性......)。

我能够使两种GUI模式都可切换,但是下框架(称为lowerframe的框架)的框架高度发生了变化,看起来非常难看。

我认为所描述的行为是帧内容的不同高度的结果。在第一种模式中有几个entry小部件,而在第二种模式中,只有一个小label小部件包含foo

如何防止框架高度动态变化?换句话说:有没有办法来修复lowerframe的高度?

我指定了height=200(以及GUI右下角的btnframe),这似乎没有任何效果,因为包含foo的标签 - 标签小部件肯定小于200像素。

--- MWE ---

#!/usr/bin/env python3
# coding: utf-8

from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk

class Window(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.parameternames = []

        # create master window
        self.master = master

        # create master window
        self.create_masterwindow()

    def create_masterwindow(self):
        """
        creates master window with menubar and sets GUI to input mode
        """
        self.master.title('GUI')
        self.master.geometry('1280x850')
        self.master.resizable(width=FALSE, height=FALSE)

        self.gui_inputmode(firstcall=True)
        self.handle_resultsbtn(firstcall=True, showbtn=False)

    def gui_inputmode(self, firstcall=False):
        """
        turn GUI inputmode on
        """
        if firstcall:
            self.master.grid_columnconfigure(0, weight=1)
            self.master.grid_rowconfigure(0, weight=1)

            self.create_upperframe()
            self.upperframe.grid(row=0, column=0, pady=20, padx=20, columnspan=2, sticky='NEW')

            self.create_lowerframe()
            self.lowerframe.grid(row=1, column=0, pady=10, padx=20, sticky='SEW')

            self.create_btnframe()
            self.btnframe.grid(row=1, column=1, pady=5, padx=20, sticky='NSEW')
            self.put_inputfields()
            self.handle_inputbtn(firstcall=True, showbtn=True)

            self.pid = ImageTk.PhotoImage(file='test_1230_510.png')

            self.pidlabel = Label(self.upperframe, image=self.pid)
            self.pidlabel.pid = self.pid  # store a reference to the image as an attribute of the widget
            self.pidlabel.grid(row=0, column=0)

        else:
            self.handle_resultsbtn(showbtn=False)
            self.handle_inputbtn()
            self.error_label.grid_remove()
            for i, subdict in enumerate(self.parameternames):
                if type(subdict) == dict:
                    self.master.nametowidget(subdict['pname_entry_table']).grid()

    def gui_resultsmode(self):
        """
        turn GUI resultsmode on
        """
        self.handle_inputbtn(showbtn=False)
        self.handle_resultsbtn()

        for i, subdict in enumerate(self.parameternames):
            if type(subdict) == dict:
                self.master.nametowidget(subdict['pname_entry_table']).grid_remove()

        self.error_label = ttk.Label(self.lowerframe, text='foo')
        self.error_label.grid(row=0, column=0, sticky='E')

    def create_upperframe(self):
        """
        creates frame for PID and loads appropriate PID (GUI input mode)
        """
        if hasattr(self, 'upperframe'):
            del self.upperframe
        self.upperframe = Frame(self.master, width=1235, height=510, relief=RIDGE, bd=2)

    def create_lowerframe(self):
        """
        creates lower frame
        """
        if hasattr(self, 'lowerframe'):
            del self.lowerframe
        self.lowerframe = Frame(self.master, relief=RIDGE, bd=2, height=200)

    def put_inputfields(self):
        """
        creates entry widgets in lowerframe to read parameter as user input (GUI input mode)
        """
        for i in range(0, 18):
            r = (i // 4)
            c = (i % 4)*3

            self.lowerframe.grid_columnconfigure(c, weight=1)
            self.lowerframe.grid_columnconfigure(c+2, weight=1)

            entry_table = Entry(self.lowerframe, width=10, justify='right')
            entry_table.insert(0, format(float(42), ".3f"))
            entry_table.grid(row=r, column=c+1, pady=5, padx=0, sticky='EW')
            subdict = {}
            subdict['pname_entry_table'] = str(entry_table)
            self.parameternames.append(subdict)

    def handle_inputbtn(self, firstcall=False, showbtn=True):
        """
        creates buttons in btnframe when GUI in input mode
        """
        if firstcall:
            self.startanalysis_btn = Button(self.btnframe, width=15, text='Start Analysis')
            self.abortanalysis_btn = Button(self.btnframe, width=15, text='Abort Analysis')
            self.resetanalysis_btn = Button(self.btnframe, width=15, text='Reset Analysis')
            self.showresults_btn = Button(self.btnframe, width=15, text='Show Results', command=self.gui_resultsmode)
        if showbtn:
            self.startanalysis_btn.grid(pady=5)
            self.abortanalysis_btn.grid(pady=5)
            self.resetanalysis_btn.grid(pady=5)
            self.showresults_btn.grid(pady=5, sticky='S')
        if not showbtn:
            self.startanalysis_btn.grid_remove()
            self.abortanalysis_btn.grid_remove()
            self.resetanalysis_btn.grid_remove()
            self.showresults_btn.grid_remove()

    def handle_resultsbtn(self, firstcall=False, showbtn=True):
        """
        creates buttons in btnframe when GUI in result mode
        """
        if firstcall:
            self.exportdata_btn = Button(self.btnframe, width=15, text='Export Data')
            self.exportgraphs_btn = Button(self.btnframe, width=15, text='Export Graphs')
            self.createreport_btn = Button(self.btnframe, width=15, text='Create Report')
            self.showinput_btn = Button(self.btnframe, width=15, text='Show Input', command=self.gui_inputmode)
        if showbtn:
            self.exportdata_btn.grid(pady=5)
            self.exportgraphs_btn.grid(pady=5)
            self.createreport_btn.grid(pady=5)
            self.showinput_btn.grid(pady=5, sticky='S')
        if not showbtn:
            self.exportdata_btn.grid_remove()
            self.exportgraphs_btn.grid_remove()
            self.createreport_btn.grid_remove()
            self.showinput_btn.grid_remove()

    def create_btnframe(self):
        """
        creates frame for buttons in lower right corner
        """
        if hasattr(self, 'btnframe'):
            del self.btnframe
        self.btnframe = Frame(self.master, width=130, height=200)
        self.btnframe.grid_rowconfigure(3, weight=1)


master = Tk()
app = Window(master)
master.mainloop()

---测试图像--- test_1230_510.png

1 个答案:

答案 0 :(得分:10)

.grid_propagate(flag)正是您要找的。

设置框架的高度和宽度后,如果禁用传播,无论您使用多少个小部件,其大小都会相同。

作为一个例子,我写了很少的代码。虽然看起来很难看,但它展示了传播是如何运作的。

import tkinter as tk

root = tk.Tk()
root.geometry("500x300")

def add():
    tk.Entry(frame).grid()

def disable():
    frame.configure(height=frame["height"],width=frame["width"])
    frame.grid_propagate(0)

def enable():
    frame.grid_propagate(1)

frame = tk.Frame(root, height=100,width=150,bg="black")
frame.grid(row=1,column=0)

tk.Button(root, text="add widget", command=add).grid(row=0,column=0)
tk.Button(root, text="disable propagation", command=disable).grid(row=0,column=1)
tk.Button(root, text="enable propagation", command=enable).grid(row=0,column=2)