我有一个小的python程序来构建GUI。我尝试使用文本小部件来创建一个包含垂直堆叠帧的易于滚动的窗口。按下按钮时会创建一个框架并添加到文本小部件的底部。这很好用;但是,我努力让这些框架伸展以水平填充文本框。
import Tkinter as tk
class NewEntry(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
#self.pack(fill="x", expand=True) #possible error source
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0,weight=1)
textField = tk.Entry(self)
textField.grid(row=1, column=0, padx=2, pady=1, sticky="ew")
addButton = tk.Button(self, text="Add", cursor="arrow")
addButton.grid(row=1, column=1, padx=10, pady=2, sticky="ew")
newLabel = tk.Label(self, text="Test", bg="#5522FF")
newLabel.grid(row=0, padx=2, pady=2, sticky="ew", columnspan=2)
newLabel.columnconfigure(0, weight=1)
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent)
self.parent=parent
self.grid()
self.columnconfigure(0, weight=1)
self.grid_rowconfigure(0,weight=1)
self.text = tk.Text(self, wrap="none", bg="#AA3333")
vsb = tk.Scrollbar(orient="vertical", command=self.text.yview)
self.text.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
self.text.pack(fill="both", expand=True)
b = tk.Button(self, text="Button #%s" % 1, command=self.OnButtonClick)
self.text.window_create("end", window=b)
self.text.insert("end", "\n")
def OnButtonClick(self):
self.text.configure(state="normal")
panel = NewEntry(self.text, bg="#FF1111")
self.text.window_create("end", window=panel)
self.text.insert("end", "\n")
self.text.configure(state="disabled")
if __name__=="__main__":
root = tk.Tk()
root.resizable(True, True)
appinstance=MainApplication(root)
appinstance.pack(fill="both", expand=True)
root.mainloop()
我已经阅读了许多不同的帖子,谈论grid_columnconfigure,填充选项,粘性选项等,但我还没有能够正确地填充它。我想知道Text小部件的window_create()方法是否会产生某种大小限制?看起来我的NewEntry类中的代码正好填充了window_create方法允许的空间,但我不知道如何创建一个"面板"填写文本框的宽度。
我也知道使用画布而不是文本框的可能性(我想要保持动态大小和可滚动性)。我从几个不同的帖子中读到,如果你有一个简单的小部件堆栈,文本小部件是最容易的。不过,我会接受任何建议。
答案 0 :(得分:0)
问题的根源是框架通常想要适合其内容。因此,当您将标签,条目小部件和按钮添加到框架时,它将缩小以适应。您给框架的任何尺寸都将被忽略。
这个问题有几种解决方案。许多人做的是关闭几何传播(例如:self.grid_propagate(False)
),但这意味着当你真正想要的是控制宽度时,你必须同时管理宽度和高度。
另一个解决方案是在面板中放置一些可以使用显式宽度配置的内容,然后这将使包含框架增长到适合。例如,您可以在第0行中添加一个不可见的框架,该框架位于第0行的其他窗口小部件后面。当您更改此框架的宽度时,它将导致包含框架增长:
class NewEntry(tk.Frame):
def __init__(...):
...
# create this _before_ creating the other widgets
# so it is lowest in the stacking order
self.sizer = tk.Frame(self, height=1)
self.sizer.grid(row=0, columnspan=2)
...
使用它,您可以通过设置sizer的宽度强制面板为您想要的任何宽度,但tkinter将继续计算窗口小部件的最佳高度:
self.sizer.configure(width=200)
现在您只需设置绑定,以便每当文本小部件更改大小时,您都可以调用此函数来调整每个条目的大小。
例如,您可能希望将所有面板保存在列表中,以便稍后可以对其进行迭代。
class MainApplication(...):
def __init__(...):
...
self.panels = []
...
def OnButtonClick(...):
...
panel = NewEntry(...)
self.panels.append(panel)
...
使用它,您可以设置一个窗口调整大小时触发的绑定:
class MainApplication(...):
def __init__(...):
...
self.text.bind("<Configure>", self.OnConfigure)
...
def OnConfigure(self, event):
for panel in self.panels:
panel.sizer.configure(width=event.width)
我不会那样做,因为它将面板的实现紧密地耦合到主窗口,但它说明了显式控制嵌入窗口宽度的一般技术。
其他解决方案涉及将面板放在包含框架内,并使该框架成为添加到文本窗口小部件的唯一窗口小部件。您还可以使用画布而不是文本小部件,因为它允许您显式设置嵌入式窗口的宽度和高度。