簡體   English   中英

如果Python小部件到達屏幕的末尾,則它們會在框架中包裝小部件

[英]Python Tkinter wrap widgets in frame if they reach the end of the screen

是否有類似Tk幾何管理器的新行包裝? 我正在使用pack將小部件放在框架內。 在高分辨率屏幕上,小部件適合並排查找。 但是,如果將其放入較小的屏幕,則小部件將在框架中用完。

基本上,我們來自:

之前

至:

后

您可以看到它如何切斷我的處理器輸入字段。 相關代碼:

options_frame = ttk.LabelFrame(
        parent_frame, text="Blast Options")
options_frame.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
        self._set_up_blast_options(options_frame)

def _set_up_blast_options(self, options_frame):
    self.evalue = Tkinter.DoubleVar()
    self.evalue.set(1)
    self.word_size = Tkinter.IntVar()
    self.word_size.set(4)
    self.penalty_mismatch = Tkinter.DoubleVar()
    self.penalty_mismatch.set(-4)
    self.min_d_match = Tkinter.IntVar()
    self.min_d_match.set(5)
    self.proc_count = Tkinter.IntVar()
    self.proc_count.set(cpu_count())

    # evalue
    e_value_label = ttk.LabelFrame(
        options_frame, text="e-Value Threshold")
    e_value_entry = ttk.Entry(e_value_label)
    e_value_entry.insert(0, self.evalue.get())
    e_value_entry.bind('<Return>', self._validate_e_value)
    e_value_entry.bind('<FocusOut>', self._validate_e_value)
    e_value_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    e_value_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

    # word size
    word_size_label = ttk.LabelFrame(
        options_frame, text="Word Size")
    word_size_entry = ttk.Entry(word_size_label)
    word_size_entry.insert(0, self.word_size.get())
    word_size_entry.bind('<Return>', self._validate_word_value)
    word_size_entry.bind('<FocusOut>', self._validate_word_value)
    word_size_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    word_size_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

    penalty_mismatch_label = ttk.LabelFrame(
        options_frame, text="Penalty Mismatch")
    penalty_mismatch_entry = ttk.Entry(penalty_mismatch_label)
    penalty_mismatch_entry.insert(0, self.penalty_mismatch.get())
    penalty_mismatch_entry.bind(
        '<Return>', self._validate_penalty_mismatch_value)
    penalty_mismatch_entry.bind(
        '<FocusOut>', self._validate_penalty_mismatch_value)
    penalty_mismatch_label.pack(side=LEFT, expand=1, pady=5,
                                padx=5, fill=X)
    penalty_mismatch_entry.pack(side=TOP, expand=1, pady=5,
                                padx=5, fill=X)
    # Min D Nucleotides
    min_d_match_label = ttk.LabelFrame(
        options_frame, text="Minimal Number of D Nucleotides")
    min_d_match_entry = ttk.Entry(min_d_match_label)
    min_d_match_entry.insert(0, self.min_d_match.get())
    min_d_match_entry.bind(
        '<Return>', self._validate_min_match_value)
    min_d_match_entry.bind(
        '<FocusOut>', self._validate_min_match_value)
    min_d_match_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    min_d_match_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

    # how many cpus to use
    proc_count_label = ttk.LabelFrame(
        options_frame, text="Processors")
    proc_count_entry = ttk.Entry(proc_count_label)
    proc_count_entry.insert(0, self.proc_count.get())
    proc_count_entry.bind(
        '<Return>', self._validate_proc_count_value)
    proc_count_entry.bind(
        '<FocusOut>', self._validate_proc_count_value)
    proc_count_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    proc_count_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

許多事件綁定和選項的設置可能不相關,但我認為我仍然應該包括...以防萬一。 最好的選擇是切換到網格管理器嗎? 問題就在於這個框架被打包在另一個框架內......依此類推。 是不是如果你開始使用網格管理器,你必須將它用於一切,因為你不能在同一幀中混合打包和網格管理器?

AFAIK沒有在tkinter中創建動態接口的內置方法。 您最好的選擇是獲得屏幕分辨率,然后適當地網格/打包。

user32 = ctypes.windll.user32
get_screensize = (user32.GetSystemMetrics(0), user32.GetSystemMetrics(1))

所以例如....

widget1 = tkinter.Entry(root,width=20,etc)
widget2 = tkinter.Label(root,text='Hello',etc)
## Now perform update_idletasks() which will force
## Tkinter to calculate their size.
widget1.update_idletasks()
widget2.update_idletasks()
## Now calculate whether they'll fit.
if widget1.winfo_width() + widget2.winfo_width() > screensize[0]:## Not enough space
    widget1.grid(row=0)
    widget2.grid(row=1)
else:## Both will fit on one line.
    widget1.grid(row=0,column=0)
    widget2.grid(row=0,column=1)

一般來說,我同意I_do_python的答案,但我會做一個小修改。 我會將所有小部件放在一個新的Frame中,我會使用Frame的寬度作為是否包裹的試金石。 並且您可以綁定"<Configure>"事件的事件處理程序,然后檢查在應用程序的窗口(以及框架)調整大小時是否需要包裝Frame的內容。

我編寫了下面的函數,它使用grid方法智能地將小部件插入到框架中。 它當然可以改進,但它適用於我。 通常,如果使用.grid()填充父級,則當填充小部件的寬度不同時,可能會浪費空白空間。 下面的函數通過將父分解為邏輯列(代碼中的divisions )並允許小部件跨越多個列來解決此問題。 結果是網格布局,大大減少了浪費的空白區域。 設置divisions越高,結果越好,但默認值應適用於大多數情況。

def smart_grid(parent, *args, **kwargs): # *args are the widgets!
    divisions   = kwargs.pop('divisions', 100)
    force_f     = kwargs.pop('force', False)
    if 'sticky' not in kwargs:
        kwargs.update(sticky='w')
    try:
        parent.win_width
    except:
        parent.win_width = -1
    winfo_width = parent.winfo_width()
    if 1 < winfo_width != parent.win_width or force_f:
        parent.win_width = winfo_width
        row = col = width = 0
        argc = len(args)
        for i in range(argc):
            widget_width = args[i].winfo_width()
            columns = max(1, int(widget_width * float(divisions) / winfo_width))
            width += widget_width
            if width > winfo_width:
                width = widget_width
                row += 1
                col = 0
            args[i].grid(row=row, column=col, columnspan=columns, **kwargs)
            col += columns
        parent.update_idletasks() # update() # 
        return row + 1

最后我會花幾分鍾用w.winfo_reqwidth()重寫它,並會更新我的帖子。

暫無
暫無

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

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