英文:
How to tkinter pack_propagate in one direction?
问题
以下是您要翻译的代码部分:
class MyWindow(tk.Tk):
def __init__(self):
super().__init__();
self.title("My Window");
# Setting up main frame on window
self.main_frame = tk.Frame(self.master);
self.main_frame.pack(fill='both', expand=True);
self.main_frame.pack_propagate(False);
self.main_frame.configure(width=500, height=500);
# Header Frame
self.header = tk.Frame(self.main_frame, height=50);
self.header.pack(side='top', fill='both');
self.header.pack_propagate(False);
# Some Header Widgets
self.button1 = tk.Button(self.header, text="button1");
self.button1.pack(side='left');
self.button2 = tk.Button(self.header, text="button2");
self.button2.pack(side='left');
# Body Frame
self.body = tk.Frame(self.main_frame);
self.body.pack(side='top', fill='both', expand=True);
self.body.pack_propagate(False);
# Scrollable Body Frame Canvas
self.canvas = tk.Canvas(self.body, bg='red');
self.canvas.pack(side='left', fill='both', expand=True);
self.scrollbar = tk.Scrollbar(self.body, command=self.canvas.yview);
self.scrollbar.pack(side='right', fill='y');
self.canvas.configure(yscrollcommand=self.scrollbar.set);
self.canvas.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox('all')));
self.canvas_frame = tk.Frame(self.canvas);
self.canvas.create_window((0, 0), window=self.canvas_frame, anchor='nw');
self.item_list = [];
for i in range(10):
self.item_list.append(self.A(self, i));
class A(tk.Frame):
def __init__(self, parent, index):
# Basic Info
self.index = index;
if self.index % 2 == 0:
self.bg_color = 'white';
else:
self.bg_color = 'gray';
super().__init__(parent.canvas_frame, bg=self.bg_color);
self.pack(side="top", fill='both');
self.parent = parent;
self.index = index;
# Sample Widgets
tk.Label(self, text="Item" + str(self.index) + ", Label1", bg=self.bg_color).pack(side="top");
tk.Label(self, text="Item" + str(self.index) + ", Label2", bg=self.bg_color).pack(side="top");
tk.Label(self, text="Item" + str(self.index) + ", Label3", bg=self.bg_color).pack(side="top");
# Plus other widgets...
if __name__ == "__main__":
window = MyWindow()
window.mainloop()
希望这对您有所帮助。如果您有其他问题,欢迎提出。
英文:
So here's my issue:
I have some class "A" that represents a commonly used format for a tkinter frame. Multiple instances of "A" are stacked on top of each other vertically representing a list of sorts (too complicated for tk.Listbox or Treeview, though). These instances are also supposed to function with a scrollbar, so I placed them in a canvas_frame, which itself is in a canvas, with the appropriate setup. My issue is this: I would like the width of these frames to extend to the edge of the window, however have heights automatically calculated by the usual Tkinter algorithm (however it works). To summarize in code:
'''
import tkinter as tk;
class MyWindow(tk.Tk):
def __init__(self):
super().__init__();
self.title("My Window");
# Setting up main frame on window
self.main_frame = tk.Frame(self.master);
self.main_frame.pack(fill = 'both', expand = True);
self.main_frame.pack_propagate(False);
self.main_frame.configure(width = 500, height = 500);
# Header Frame
self.header = tk.Frame(self.main_frame, height = 50);
self.header.pack(side = 'top', fill = 'both');
self.header.pack_propagate(False);
# Some Header Widgets
self.button1 = tk.Button(self.header, text = "button1");
self.button1.pack(side = 'left');
self.button2 = tk.Button(self.header, text = "button2");
self.button2.pack(side = 'left');
# Body Frame
self.body = tk.Frame(self.main_frame);
self.body.pack(side = 'top', fill = 'both', expand = True);
self.body.pack_propagate(False);
# Scrollable Body Frame Canvas
self.canvas = tk.Canvas(self.body, bg = 'red');
self.canvas.pack(side = 'left', fill = 'both', expand = True);
self.scrollbar = tk.Scrollbar(self.body, command = self.canvas.yview);
self.scrollbar.pack(side = 'right', fill = 'y');
self.canvas.configure(yscrollcommand = self.scrollbar.set);
self.canvas.bind("<Configure>", lambda e: self.canvas.configure(scrollregion = self.canvas.bbox('all')));
self.canvas_frame = tk.Frame(self.canvas);
self.canvas.create_window((0,0), window = self.canvas_frame, anchor = 'nw');
self.item_list = [];
for i in range(10):
self.item_list.append(self.A(self, i));
class A(tk.Frame):
def __init__(self, parent, index):
# Basic Info
self.index = index;
if self.index % 2 == 0:
self.bg_color = 'white';
else:
self.bg_color = 'gray';
super().__init__(parent.canvas_frame, bg = self.bg_color);
self.pack(side = "top", fill = 'both');
self.parent = parent;
self.index = index;
# Sample Widgets
tk.Label(self, text = "Item" + str(self.index) + ", Label1", bg = self.bg_color).pack(side = "top");
tk.Label(self, text = "Item" + str(self.index) + ", Label2", bg = self.bg_color).pack(side = "top");
tk.Label(self, text = "Item" + str(self.index) + ", Label3", bg = self.bg_color).pack(side = "top");
# Plus other widgets...
if __name__ == "__main__":
window = MyWindow()
window.mainloop()
As I stated, my goal is to have each row/"A" frame fill the window/canvas horizontally, but be distributed vertically based on their internal widgets. I belive this is handled by pack_propagate (I may be wrong).
In other words: how do I pack propagate in only one direction?
I tried two solutions:
First is to keep pack_propagate on, but to set the width of the widgets automatically. So within the MyWindow class, I added the following:
self.bind("<Configure>", self.resize);
def resize(self, event):
for item in self.item_list:
item.config(width = event.width);
however when I try this, I think the program ends up in a loop, where each resize changes the width of the frame (due to pack_propagate) and in turn, calls the resize function again.
My second was to turn off pack_propagate, and to try and to do the same thing, but then the height of each "A" instance is 1 and doesn't size automatically.
答案1
得分: 1
你可以在self.canvas
上的<Configure>
事件的回调函数内,将self.canvas_frame
的宽度设置为self.canvas
的宽度:
class MyWindow(tk.Tk):
def __init__(self):
...
#self.canvas.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox('all')))
self.canvas_frame = tk.Frame(self.canvas)
self.internal = self.canvas.create_window((0,0), window=self.canvas_frame, anchor='nw')
self.canvas.bind("<Configure>", lambda e: self.canvas.itemconfig(self.internal, width=e.width))
self.canvas_frame.bind("<Configure>", lambda e: self.canvas.config(scrollregion=self.canvas.bbox("all")))
...
请注意,canvas
的scrollregion
应在内部框架被调整大小时更新,而不是在canvas本身被调整大小时更新。
另外,行尾的分号';'
不是必需的。
英文:
You can set the width of self.canvas_frame
to the width of self.canvas
inside the callback of <Configure>
event on self.canvas
:
class MyWindow(tk.Tk):
def __init__(self):
...
#self.canvas.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox('all')))
self.canvas_frame = tk.Frame(self.canvas);
self.internal = self.canvas.create_window((0,0), window=self.canvas_frame, anchor='nw')
self.canvas.bind("<Configure>", lambda e: self.canvas.itemconfig(self.internal, width=e.width))
self.canvas_frame.bind("<Configure>", lambda e: self.canvas.config(scrollregion=self.canvas.bbox("all")))
...
Note that scrollregion
of the canvas should be updated whenever the internal frame is resized, not the canvas itself.
Also those ;
at the end of lines are not necessary.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论