【问题标题】:Changing Tab Order of Frames in Tkinter在 Tkinter 中更改帧的 Tab 顺序
【发布时间】:2017-10-25 17:09:45
【问题描述】:

总结

我如何lift (tk_raise) 一个框架中包含的 Tab 键顺序小部件位于另一个框架中包含的小部件之上,该小部件首先创建?

完整版

我有一个 Tkinter 表单,为此我将多个小部件分组到框架中,然后使用网格布局将框架定位到窗口中。在我的特定用例中,框架是派生自 ttk.Frame 的类,但这对这个问题没有任何影响,因为就本问题而言,它对表单行为没有影响。

对于我的用例,在循环中创建多个帧是有意义的,以避免代码重复。正如预期的那样,小部件的 Tab 键顺序是创建它们的顺序。但是,在这种情况下,表单的自然流程是按以下顺序在小部件之间切换:[0, 1, 2, 3, 4, 10, 11, 12, 5, 6, 7, 8, 9](参见下面的MCVE)。

在包含小部件 10-12 的框架上执行 lift 不会更改 Tab 键顺序。但是,对小部件 10-12 执行单独的提升会产生以下异常:

_tkinter.TclError: can't raise ".tabtest.frame_2.widget_10" above ".tabtest.frame_1.widget_5

这应该是可行的,但是怎么做呢?

编辑

正如 cmets(下)所述,乍一看,这可能是问题 "How to set the tab order in a tkinter application?" 的重复。在提交我的问题之前,我审查了这个问题。但是,此问题的answer 专门引用了为单个框架内的小部件设置选项卡顺序。当我运行答案中包含的示例时,它按预期工作。但是,将其应用于我的用例时:

  • 尝试抬起框架不会导致选项卡行为发生变化。

  • 尝试提升框架中包含的各个小部件会产生上述错误。

MCVE

使用 Python 3.4 编写。

import tkinter as tk
from tkinter import ttk

class TabTest(ttk.Frame):
    def __init__(self, master, *args, **kwargs):
        super().__init__(master, *args, **kwargs)

        # Remove row/column weights.
        for i in range(50):
            self.rowconfigure(i, weight=0)
            self.columnconfigure(i, weight=0)

        # Entry fields.
        frames = []
        entries = []

        x = 0
        for i in range(2):
            f = ttk.Frame(self, takefocus=0, name='frame_{}'.format(i))
            for j in range(5):
                e = ttk.Entry(f, name='widget_{}'.format(x))
                entries.append(e)
                e.insert(tk.END, 'Widget {}'.format(x))
                e.pack(side='top', anchor='w')
                x += 1

            frames.append(f)

        # Buttons
        buttons = []
        f = ttk.Frame(self, takefocus=0, name='frame_2')
        for i in range(3):
            b = ttk.Button(f, text='Widget {}'.format(x),
                           name='widget_{}'.format(x))  
            buttons.append(b)
            b.pack(fill='x')
            x += 1

        frames.append(f)

        frames[0].grid(row=0, column=0, rowspan=5, columnspan=2,
                       padx=2, pady=2, sticky='news')
        frames[2].grid(row=0, column=2, rowspan=5, columnspan=2,
                       padx=2, pady=2, sticky='news')
        frames[1].grid(row=0, column=4, rowspan=5, columnspan=2,
                       padx=2, pady=2, sticky='news')

        frames[2].lift()  # No difference in tab order.
#         for btn in buttons:
#             btn.lift(entries[5])  # Generates exception: _tkinter.TclError: can't raise ".tabtest.frame_2.widget_10" above ".tabtest.frame_1.widget_5

        self.buttons = buttons
        self.frames = frames
        self.entries = entries

        self.pack(fill='both')
        root = self._root()
        root.update()
        root.minsize(root.winfo_width(), root.winfo_height())



def main():
    root = tk.Tk()
    app = TabTest(root, name='tabtest')
    root.mainloop()



if __name__ == '__main__':
    main()

【问题讨论】:

  • @PRMoureu - 谢谢,但用例略有不同。那是我根据我的需要找到并测试的。请注意,它特别提到在单个框架中打包多个小部件,而不是在多个框架中。当我从this answer 执行代码时,它按预期工作。但是,在我的示例中以相同的方式执行它会产生我注意到的异常。
  • 它似乎与new_order = (frames[0], frames[2], frames[1]) 或@Novel 提供的相同方式工作正常
  • ...既然我这样做了,照原样,你是对的:它确实以同样的方式工作。但是为什么简单的obj1.lift(obj0) 不能按预期工作呢?

标签: python python-3.x tkinter


【解决方案1】:

你可以按照你想要的顺序调用lift()而不为所有帧提供参数:

for idx in [0,2,1]:
    frames[idx].lift()

【讨论】:

  • 这似乎有效。不是最佳解决方案,但可以正常工作。我宁愿只执行一次提升。
【解决方案2】:

您可以反转逻辑,并将lower 应用于frames[1]

frames[1].lower()

而不是frames[2].lift(frames[1])

【讨论】:

  • 嗯。刚试过。这样做是将frames[1] 放在tab 顺序的第一位,所以第一个<Tab> 移动到小部件5。我可能会这样做,但还不确定。
  • 否则我发现了这个post
猜你喜欢
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 2021-12-21
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多