【问题标题】:Python Tkinter wrap widgets in frame if they reach the end of the screen如果小部件到达屏幕末尾,Python Tkinter 会将小部件包装在框架中
【发布时间】:2013-11-29 12:59:54
【问题描述】:

对于 Tk 几何管理器,是否有类似 pack to new line 的东西?我正在使用包将小部件放在框架内。在高分辨率屏幕上,小部件适合并排查找。但是,如果你把它放到一个较小的屏幕上,小部件会在框架中用完。

基本上,我们从:

到:

您可以看到它是如何切断我的处理器输入字段的。相关代码:

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)

许多事件绑定和选项设置可能不相关,但我认为我仍然应该包括...以防万一。最好的选择是切换到网格管理器吗?问题是这个框架被包装在另一个框架内......等等。是不是一开始用网格管理器,就什么都得用,因为不能在同一个框架里混用打包和网格管理器?

【问题讨论】:

  • 您可以在同一个应用程序中混合使用 pack 和 grid —— 事实上,这是推荐的做法。您不能将 grid 和 pack 与具有相同父级的小部件混合使用。

标签: python user-interface tkinter tk ttk


【解决方案1】:

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)

【讨论】:

    【解决方案2】:

    总的来说,我同意 I_do_python 的回答,但我会做一些小的修改。我会将所有小部件放在一个新框架中,并使用框架的宽度作为是否换行的试金石。您可以为"&lt;Configure&gt;" 事件绑定一个事件处理程序,然后检查当应用程序的窗口(以及框架)调整大小时是否需要包装框架的内容。

    我编写了以下函数,它使用网格方法智能地将小部件插入框架。它当然可以改进,但它对我有用。通常,如果您使用.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() 重写它并更新我的帖子。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-29
      • 2020-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多