tkinter frame:更改内容时固定框架高度
tkinter frame: fix frame height when changing its content
我正在开发一个带有适当 GUI 的自写模拟工具。通常有两种主要的用户模式。在第一个中,用户可以为所需的计算输入多个值。所有计算完成后,用户可以通过点击右下角的"Show Results"按钮切换到"results mode"。通过这样做,GUI 上部带有图像的主要 window 不会改变。但是,之前在 GUI 下部的输入条目应该更改为消息区域,其中显示错误、警告或其他信息(持续时间、收敛性、...)。
我可以让两种GUI模式都可以切换,但是下面的框架(称为lowerframe
的框架)的框架高度发生了变化,看起来很难看。
我认为所描述的行为是框架内容的不同高度造成的。在第一种模式中有几个 entry
小部件,而在第二种模式中只有一个小 label
小部件包含 foo
.
如何防止框架的高度动态变化?换句话说:有没有办法固定 lowerframe
?
的高度
我指定了 height=200
(以及 GUI 右下角的 btnframe
),这似乎没有任何效果,因为包含 foo
的框架-label widget 绝对小于那些 200 px.
--- 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()
--- 测试图像 ---
.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)
我正在开发一个带有适当 GUI 的自写模拟工具。通常有两种主要的用户模式。在第一个中,用户可以为所需的计算输入多个值。所有计算完成后,用户可以通过点击右下角的"Show Results"按钮切换到"results mode"。通过这样做,GUI 上部带有图像的主要 window 不会改变。但是,之前在 GUI 下部的输入条目应该更改为消息区域,其中显示错误、警告或其他信息(持续时间、收敛性、...)。
我可以让两种GUI模式都可以切换,但是下面的框架(称为lowerframe
的框架)的框架高度发生了变化,看起来很难看。
我认为所描述的行为是框架内容的不同高度造成的。在第一种模式中有几个 entry
小部件,而在第二种模式中只有一个小 label
小部件包含 foo
.
如何防止框架的高度动态变化?换句话说:有没有办法固定 lowerframe
?
我指定了 height=200
(以及 GUI 右下角的 btnframe
),这似乎没有任何效果,因为包含 foo
的框架-label widget 绝对小于那些 200 px.
--- 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()
--- 测试图像 ---
.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)