簡體   English   中英

Tkinter:網格內的網格或包裝?

[英]Tkinter: grid or pack inside a grid?

我正在構建一個軟件的GUI,並希望實現這一目標:

######################################
#             |      some title      #
# menu upper  |----------------------#
#             |                      #
#             |         CANVAS       #
# menu lower  |                      #
#             |                      #
#------------------------------------#
#              statusbar             #
######################################

菜單上部具有一些高級功能, 菜單下限根據用戶輸入而變化。 狀態欄經常更改其內容。


不幸的是,Tkinter拒絕工作。

使用網格布局管理器我無法創建穩定的設計,並在左側的菜單中添加標簽和按鈕等內容:

self.root = tk.Tk()
self.root.resizable(width=0, height=0)
self.root.title("some application")

# menu left
self.menu_left = tk.Frame(self.root, width=150, bg="#ababab")
self.menu_left.grid(row=0, column=0, rowspan=2, sticky="ns")

self.menu_left_upper = tk.Frame(self.menu_left, width=150, height=150, bg="red")
self.menu_left_upper.grid(row=0, column=0)

# this label breaks the design   
#self.test = tk.Label(self.menu_left_upper, text="test")
#self.test.pack()

self.menu_left_lower = tk.Frame(self.menu_left, width=150, bg="blue")
self.menu_left_lower.grid(row=1, column=0)

# right area
self.some_title_frame = tk.Frame(self.root, bg="#dfdfdf")
self.some_title_frame.grid(row=0, column=1, sticky="we")

self.some_title = tk.Label(self.some_title_frame, text="some title", bg="#dfdfdf")
self.some_title.pack()

self.canvas_area = tk.Canvas(self.root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)

self.root.mainloop()

這種設計在左側的菜單中沒有內容 每當我在self.menu_left_upperself.menu_left_lower添加一些東西時,就像test標簽一樣,我的設計破了:菜單框架消失了。 另外,即使有了柱子 ,我也不得不刪除狀態欄,因為當它被添加時,左邊的菜單再次消失了。


使用包布局管理器我得到了這個:

######################################
#             |      some title      #
#             |----------------------#
# menu upper  |                      #
#             |         CANVAS       #
#             |                      #
# menu lower  |                      #
#             |----------------------#
#             |       statusbar      #
######################################

因為我希望左邊的菜單框架消耗完整的y空間,所以我使用它來增長pack(side="left", expand=True, fill="both") ,但是這個設置總是拒絕狀態欄去全寬。

此外,純包管理器代碼看起來“丑陋” 我認為使用網格管理器的設計更“清晰”。 因此我認為網格布局中的網格或包布局會很好嗎?


有人可以幫忙嗎? 我陷入了GUI-hell:/

做布局的關鍵是有條不紊,並使用正確的工具來完成工作。 這也意味着有時你需要有創意。 這意味着在grid放置東西時使用grid grid ,而在從上到下或從左到右鋪設時使用pack

另一個關鍵是將布局代碼組合在一起。 當它在一個代碼塊中時,可視化和修改布局要容易得多。

在您的情況下,您似乎有三個或四個不同的區域,具體取決於您的計算方式。 如果要使用grid ,最簡單的方法是將“菜單上部”和“菜單下部”組合到一個框架中,並將整個框架視為表格單元格。 看起來你已經在做了,這很好。

那么,讓我們從這些主要領域開始:

self.menu_left.grid(row=0, column=0, rowspan=2, sticky="nsew")
self.some_title_frame.grid(row=0, column=1, sticky="ew")
self.canvas_area.grid(row=1, column=1, sticky="nsew") 
# you don't have a status bar in the example code, but if you
# did, this is where you would put it
# self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")

無論何時使用grid ,您都需要為至少一行和一列提供正權重,以便tkinter知道在何處使用任何未分配的空間。 通常有一個小部件是“主”小部件。 在這種情況下,它是畫布。 您希望確保畫布的行和列的權重為1(一):

self.root.grid_rowconfigure(1, weight=1)
self.root.grid_columnconfigure(1, weight=1)

注意:使用pack代替grid可以節省兩行代碼,因為pack不需要像grid那樣設置權重。

接下來,我們需要解決菜單區域的問題。 默認情況下,框架會縮小以適合其內容,這就是添加標簽會破壞布局的原因。 你沒有告訴tkinter如何處理額外的空間,所以框架縮小以適應,並且額外的空間未被使用。

由於您希望“menu_upper”和“menu_lower”分別占該區域的50%,因此pack是最簡單的解決方案。 您可以使用grid ,但需要更多代碼行來添加行和列權重。

self.menu_left_upper.pack(side="top", fill="both", expand=True)
self.menu_left_lower.pack(side="top", fill="both", expand=True)

這是一個功能正常的版本,帶有狀態欄。 請注意它在調整窗口大小時的行為方式:

import Tkinter as tk

class Example():
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("some application")

        # menu left
        self.menu_left = tk.Frame(self.root, width=150, bg="#ababab")
        self.menu_left_upper = tk.Frame(self.menu_left, width=150, height=150, bg="red")
        self.menu_left_lower = tk.Frame(self.menu_left, width=150, bg="blue")

        self.test = tk.Label(self.menu_left_upper, text="test")
        self.test.pack()

        self.menu_left_upper.pack(side="top", fill="both", expand=True)
        self.menu_left_lower.pack(side="top", fill="both", expand=True)

        # right area
        self.some_title_frame = tk.Frame(self.root, bg="#dfdfdf")

        self.some_title = tk.Label(self.some_title_frame, text="some title", bg="#dfdfdf")
        self.some_title.pack()

        self.canvas_area = tk.Canvas(self.root, width=500, height=400, background="#ffffff")
        self.canvas_area.grid(row=1, column=1)

        # status bar
        self.status_frame = tk.Frame(self.root)
        self.status = tk.Label(self.status_frame, text="this is the status bar")
        self.status.pack(fill="both", expand=True)

        self.menu_left.grid(row=0, column=0, rowspan=2, sticky="nsew")
        self.some_title_frame.grid(row=0, column=1, sticky="ew")
        self.canvas_area.grid(row=1, column=1, sticky="nsew") 
        self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")

        self.root.grid_rowconfigure(1, weight=1)
        self.root.grid_columnconfigure(1, weight=1)

        self.root.mainloop()

Example()

在一個不相關的說明:我強烈建議您不要刪除用戶調整窗口大小的能力。 他們比你更了解他們的要求。 如果您正確使用gridpack ,GUI將完美調整大小。

self.root.mainloop()之前添加以下代碼可以實現您正在尋找的內容

self.some_status = tk.Label(self.root, text="status bar", bg="#dfdfdf")
self.some_status.grid(row=3, column=0, columnspan=2, sticky="we")

通過加入:

menu_left_upper.grid_propagate(False) 

在你的menu_left_upper框架和menu_left_upper.mainloop()

這適用於:

默認情況下,容器窗口小部件會擴展或折疊,以便足以容納其內容。 因此,當您調用pack時,會導致幀縮小。 此功能稱為幾何體傳播

對於絕大多數應用程序,這是您想要的行為。 對於那些您想要明確設置容器大小的罕見情況,您可以關閉此功能。 要關閉它,請在容器上調用pack_propagategrid_propagate (取決於您是否在該容器上使用grid或pack),將其賦值為False

請參閱另一個問題的鏈接

要獲取狀態欄,只需實現另一個框架和網格方法:

status_bar_frame = Frame(root, bg="#dfdfdf")
status_bar_frame.grid(row=3, column=0, columnspan=2, sticky="we")

status_bar = Label(status_bar_frame, text="status bar", bg="#dfdfdf")
status_bar.pack()

然后你的計划有效。 希望能幫助到你 :)

PS。 還有為什么所有的self屬性?

編輯:你需要做的工作:

menu_left_upper = Frame(menu_left, width=225, height=225, bg="red")
menu_left_upper.grid_propagate(False)
menu_left_upper.grid(row=0, column=0)

# this label breaks the design   
test = Label(menu_left_upper, text="test", bg='red')
test.grid()

我的結果

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM