英文:
Tkinter - Limit Tab Sequence To The Focused Frame
问题
当在运行以下代码时,反复按下TAB键,您会注意到焦点输入小部件会在所有输入小部件之间循环。我想知道是否有一种简单的方法,使TAB键只在“选定框架”中循环输入小部件。
import tkinter as tk
class Frame_Tab:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x350')
self.root.title('Frame Tab')
self.dg = '#c0c0c0'
self.bg = '#54ed58'
self.lg = '#c9c9c9'
self.frame1 = tk.LabelFrame(self.root, highlightcolor=self.bg, highlightthickness=3, highlightbackground=self.dg, padx=5, pady=5)
self.frame1.pack()
self.f1heading = tk.Button(self.frame1, text='Frame 1', takefocus=0, bg=self.lg, fg='black', height=1, borderwidth=5, command=lambda: self.f1e1.focus(), relief=tk.RAISED, font=('Arial', 12))
self.f1heading.grid(row=0, column=0, columnspan=2, ipadx=10)
self.f1l1 = tk.Label(self.frame1, text='Frame1 Entry1', font=('Arial', 12))
self.f1l1.grid(row=1, column=0, pady=5)
self.f1e1 = tk.Entry(self.frame1, width=8, bg='white', fg='black', font=('Arial', 12))
self.f1e1.grid(row=1, column=1, pady=5)
self.f1l2 = tk.Label(self.frame1, text='Frame1 Entry2', font=('Arial', 12))
self.f1l2.grid(row=2, column=0, pady=5)
self.f1e2 = tk.Entry(self.frame1, width=8, bg='white', fg='black', font=('Arial', 12))
self.f1e2.grid(row=2, column=1, pady=5)
self.frame2 = tk.LabelFrame(self.root, highlightcolor=self.bg, highlightthickness=3, highlightbackground=self.dg, padx=5, pady=5)
self.frame2.pack(pady=10)
self.f2heading = tk.Button(self.frame2, text='Frame 2', takefocus=0, bg=self.lg, fg='black', height=1, borderwidth=5, command=lambda: self.f2e1.focus(), relief=tk.RAISED, font=('Arial', 12))
self.f2heading.grid(row=0, column=0, columnspan=2, ipadx=10)
self.f2l1 = tk.Label(self.frame2, text='Frame1 Entry1', font=('Arial', 12))
self.f2l1.grid(row=1, column=0, pady=5)
self.f2e1 = tk.Entry(self.frame2, width=8, bg='white', fg='black', font=('Arial', 12))
self.f2e1.grid(row=1, column=1, pady=5)
self.f2l2 = tk.Label(self.frame2, text='Frame1 Entry2', font=('Arial', 12))
self.f2l2.grid(row=2, column=0, pady=5)
self.f2e2 = tk.Entry(self.frame2, width=8, bg='white', fg='black', font=('Arial', 12))
self.f2e2.grid(row=2, column=1, pady=5)
self.f2l3 = tk.Label(self.frame2, text='Frame1 Entry3', font=('Arial', 12))
self.f2l3.grid(row=3, column=0, pady=5)
self.f2e3 = tk.Entry(self.frame2, width=8, bg='white', fg='black', font=('Arial', 12))
self.f2e3.grid(row=3, column=1, pady=5)
self.root.mainloop()
if __name__ == '__main__':
Frame_Tab()
英文:
When repeatedly pressing the TAB key while running the code below you'll note that the focused entry widget cycles through all the entry widgets. I would like to know if there's a simple way to make the tab only cycle through the entry widgets in the "selected frame".
import tkinter as tk
class Frame_Tab:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x350')
self.root.title('Frame Tab')
self.dg = '#c0c0c0'
self.bg = '#54ed58'
self.lg = '#c9c9c9'
self.frame1 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame1.pack()
self.f1heading = tk.Button(self.frame1,text='Frame 1',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,command=lambda:self.f1e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f1heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f1l1 = tk.Label(self.frame1,text='Frame1 Entry1',font=('Arial',12))
self.f1l1.grid(row=1,column=0,pady=5)
self.f1e1 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e1.grid(row=1,column=1,pady=5)
self.f1l2 = tk.Label(self.frame1,text='Frame1 Entry2',font=('Arial',12))
self.f1l2.grid(row=2,column=0,pady=5)
self.f1e2 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e2.grid(row=2,column=1,pady=5)
self.frame2 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame2.pack(pady=10)
self.f2heading = tk.Button(self.frame2,text='Frame 2',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,command=lambda:self.f2e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f2heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f2l1 = tk.Label(self.frame2,text='Frame1 Entry1',font=('Arial',12))
self.f2l1.grid(row=1,column=0,pady=5)
self.f2e1 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e1.grid(row=1,column=1,pady=5)
self.f2l2 = tk.Label(self.frame2,text='Frame1 Entry2',font=('Arial',12))
self.f2l2.grid(row=2,column=0,pady=5)
self.f2e2 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e2.grid(row=2,column=1,pady=5)
self.f2l3 = tk.Label(self.frame2,text='Frame1 Entry3',font=('Arial',12))
self.f2l3.grid(row=3,column=0,pady=5)
self.f2e3 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e3.grid(row=3,column=1,pady=5)
self.root.mainloop()
if __name__ == '__main__':
Frame_Tab()
答案1
得分: 1
好的,以下是您要的代码部分的翻译:
我放弃尝试使这个修改后的代码正确格式化! SMH(感谢代码格式编辑)
我找到了一个解决方案,但它有点像黑客。下面的代码与上面相同,具有以下更改:
1) 我创建了一个包含应用程序中所有Entry小部件的列表
self.allEntry = [self.f1e1,self.f1e2,self.f2e1,self.f2e2,self.f2e3]
2) 然后,我将每个Entry小部件绑定到FocusIn事件。绑定调用适用于Entry小部件所在的框架的函数(self.set1或self.set2)
3) 然后,我定义了set1,set2和setTakeFocus - 这些函数可以在下面的代码末尾找到,应该是不言自明的。
代码:
import tkinter as tk
class Frame_Tab:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x350')
self.root.title('Frame Tab')
self.dg = '#c0c0c0'
self.bg = '#54ed58'
self.lg = '#c9c9c9'
self.frame1 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame1.pack()
self.f1heading = tk.Button(self.frame1,text='Frame 1',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,command=lambda:self.f1e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f1heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f1l1 = tk.Label(self.frame1,text='Frame1 Entry1',font=('Arial',12))
self.f1l1.grid(row=1,column=0,pady=5)
self.f1e1 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e1.grid(row=1,column=1,pady=5)
self.f1e1.bind('<FocusIn>',self.set1)
self.f1l2 = tk.Label(self.frame1,text='Frame1 Entry2',font=('Arial',12))
self.f1l2.grid(row=2,column=0,pady=5)
self.f1e2 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e2.grid(row=2,column=1,pady=5)
self.f1e2.bind('<FocusIn>',self.set1)
self.frame2 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame2.pack(pady=10)
self.f2heading = tk.Button(self.frame2,text='Frame 2',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,command=lambda:self.f2e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f2heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f2l1 = tk.Label(self.frame2,text='Frame1 Entry1',font=('Arial',12))
self.f2l1.grid(row=1,column=0,pady=5)
self.f2e1 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e1.grid(row=1,column=1,pady=5)
self.f2e1.bind('<FocusIn>',self.set2)
self.f2l2 = tk.Label(self.frame2,text='Frame1 Entry2',font=('Arial',12))
self.f2l2.grid(row=2,column=0,pady=5)
self.f2e2 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e2.grid(row=2,column=1,pady=5)
self.f2e2.bind('<FocusIn>',self.set2)
self.f2l3 = tk.Label(self.frame2,text='Frame1 Entry3',font=('Arial',12))
self.f2l3.grid(row=3,column=0,pady=5)
self.f2e3 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e3.grid(row=3,column=1,pady=5)
self.f2e3.bind('<FocusIn>',self.set2)
self.allEntry = [self.f1e1,self.f1e2,self.f2e1,self.f2e2,self.f2e3]
self.root.mainloop()
def set1(self,e=None):
keep = [self.f1e1,self.f1e2]
self.setTakeFocus(keep)
def set2(self,e=None):
keep = [self.f2e1,self.f2e2,self.f2e3]
self.setTakeFocus(keep)
def setTakeFocus(self,keep):
for e in self.allEntry:
if e in keep:
e.config(takefocus=1)
else:
e.config(takefocus=0)
if __name__ == '__main__':
Frame_Tab()
希望这对您有所帮助!
英文:
OK, I give up on trying to get this revised code to format correctly! SMH (THANKS for the code format edit)
I have found a solution, but it is somewhat of a hack. The code below is the same as above with the following changes:
-
I create a list of ALL Entry widgets in the applications
self.allEntry = [self.f1e1,self.f1e2,self.f2e1,self.f2e2,self.f2e3]
-
I then bind each Entry widget to the FocusIn event. The binds call a function applicable to the Frame the Entry widget is in (self.set1 or self.set2)
-
I then define set1, set2, and setTakeFocus - each of these functions can be found near the end of the code below and should be self-explanatory.
Code:
import tkinter as tk
class Frame_Tab:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x350')
self.root.title('Frame Tab')
self.dg = '#c0c0c0'
self.bg = '#54ed58'
self.lg = '#c9c9c9'
self.frame1 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame1.pack()
self.f1heading = tk.Button(self.frame1,text='Frame 1',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,command=lambda:self.f1e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f1heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f1l1 = tk.Label(self.frame1,text='Frame1 Entry1',font=('Arial',12))
self.f1l1.grid(row=1,column=0,pady=5)
self.f1e1 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e1.grid(row=1,column=1,pady=5)
self.f1e1.bind('<FocusIn>',self.set1)
self.f1l2 = tk.Label(self.frame1,text='Frame1 Entry2',font=('Arial',12))
self.f1l2.grid(row=2,column=0,pady=5)
self.f1e2 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e2.grid(row=2,column=1,pady=5)
self.f1e2.bind('<FocusIn>',self.set1)
self.frame2 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame2.pack(pady=10)
self.f2heading = tk.Button(self.frame2,text='Frame 2',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,command=lambda:self.f2e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f2heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f2l1 = tk.Label(self.frame2,text='Frame1 Entry1',font=('Arial',12))
self.f2l1.grid(row=1,column=0,pady=5)
self.f2e1 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e1.grid(row=1,column=1,pady=5)
self.f2e1.bind('<FocusIn>',self.set2)
self.f2l2 = tk.Label(self.frame2,text='Frame1 Entry2',font=('Arial',12))
self.f2l2.grid(row=2,column=0,pady=5)
self.f2e2 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e2.grid(row=2,column=1,pady=5)
self.f2e2.bind('<FocusIn>',self.set2)
self.f2l3 = tk.Label(self.frame2,text='Frame1 Entry3',font=('Arial',12))
self.f2l3.grid(row=3,column=0,pady=5)
self.f2e3 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e3.grid(row=3,column=1,pady=5)
self.f2e3.bind('<FocusIn>',self.set2)
self.allEntry = [self.f1e1,self.f1e2,self.f2e1,self.f2e2,self.f2e3]
self.root.mainloop()
def set1(self,e=None):
keep = [self.f1e1,self.f1e2]
self.setTakeFocus(keep)
def set2(self,e=None):
keep = [self.f2e1,self.f2e2,self.f2e3]
self.setTakeFocus(keep)
def setTakeFocus(self,keep):
for e in self.allEntry:
if e in keep:
e.config(takefocus=1)
else:
e.config(takefocus=0)
if __name__ == '__main__':
Frame_Tab()
答案2
得分: 1
这将导致可用性问题,如果您的用户只使用键盘,因为这将使得无法遍历到下一个框架,除非您提供一种用户切换框架的方法。
话虽如此,最简单的解决方案可能是简单地为每个组中的最后一个小部件添加自定义绑定,以将焦点移动到组中的第一个小部件。
例如,以下函数将使得在传入的第二个小部件中按下Tab键将焦点移动到第一个小部件,按下Shift-Tab键在第一个小部件上将焦点移动到第二个小部件。
def _set_tab_bindings(self, w1, w2):
w2.bind("<Tab>", lambda event: w1.focus_set() or "break")
w1.bind("<Shift-Tab>", lambda event: w2.focus_set() or "break")
然后,您可以在创建每个框架的代码中调用此函数。
self._set_tab_bindings(self.f1e1, self.f1e2)
self._set_tab_bindings(self.f2e1, self.f2e3)
这可能不是最优雅的解决方案,但可以说是最直接的解决方案。
英文:
This will lead to usability problems if your users only use the keyboard, since it will make it impossible to traverse to the next frame unless you provide some way for the user to switch frames.
That being said, the simplest solution might be to simply add a custom binding for the last widget in each group to move the first to the first widget in the group.
For example, the following function will make it so that pressing tab in the second widget that is passed in will move focus to the first, and pressing shift-tab in the first will move focus to the second.
def _set_tab_bindings(self, w1, w2):
w2.bind("<Tab>", lambda event: w1.focus_set() or "break")
w1.bind("<Shift-Tab>", lambda event: w2.focus_set() or "break")
You can then call this in the code that creates each frame.
self._set_tab_bindings(self.f1e1, self.f1e2)
self._set_tab_bindings(self.f2e1, self.f2e3)
This might not be the most elegant solution, but arguably it's the most straight-forward.
答案3
得分: 0
以下是翻译好的部分:
# 仅适用于版本3.9及以下
# 我通过简单地将最后的输入小部件绑定到"Tab FocusOut"来实现这一点。所以如果按下Tab键并且焦点离开,您会聚焦在第一个输入小部件上。所以只需添加这两行:
self.f1e2.bind("<Tab> <FocusOut>", lambda refocus: self.f1e1.focus())
self.f2e3.bind("<Tab> <FocusOut>", lambda refocus: self.f2e1.focus())
# 对我来说似乎有效。完整代码如下:
import tkinter as tk
class Frame_Tab:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x350')
self.root.title('Frame Tab')
self.dg = '#c0c0c0'
self.bg = '#54ed58'
self.lg = '#c9c9c9'
self.frame1 = tk.LabelFrame(self.root, highlightcolor=self.bg, highlightthickness=3, highlightbackground=self.dg, padx=5, pady=5)
self.frame1.pack()
self.f1heading = tk.Button(self.frame1, text='Frame 1', takefocus=0, bg=self.lg, fg='black', height=1, borderwidth=5, command=lambda: self.f1e1.focus(), relief=tk.RAISED, font=('Arial', 12))
self.f1heading.grid(row=0, column=0, columnspan=2, ipadx=10)
self.f1l1 = tk.Label(self.frame1, text='Frame1 Entry1', font=('Arial', 12))
self.f1l1.grid(row=1, column=0, pady=5)
self.f1e1 = tk.Entry(self.frame1, width=8, bg='white', fg='black', font=('Arial', 12))
self.f1e1.grid(row=1, column=1, pady=5)
self.f1l2 = tk.Label(self.frame1, text='Frame1 Entry2', font=('Arial', 12))
self.f1l2.grid(row=2, column=0, pady=5)
self.f1e2 = tk.Entry(self.frame1, width=8, bg='white', fg='black', font=('Arial', 12))
self.f1e2.grid(row=2, column=1, pady=5)
self.f1e2.bind("<Tab> <FocusOut>", lambda refocus: self.f1e1.focus()) # 这里
self.frame2 = tk.LabelFrame(self.root, highlightcolor=self.bg, highlightthickness=3, highlightbackground=self.dg, padx=5, pady=5)
self.frame2.pack(pady=10)
self.f2heading = tk.Button(self.frame2, text='Frame 2', takefocus=0, bg=self.lg, fg='black', height=1, borderwidth=5, command=lambda: self.f2e1.focus(), relief=tk.RAISED, font=('Arial', 12))
self.f2heading.grid(row=0, column=0, columnspan=2, ipadx=10)
self.f2l1 = tk.Label(self.frame2, text='Frame1 Entry1', font=('Arial', 12))
self.f2l1.grid(row=1, column=0, pady=5)
self.f2e1 = tk.Entry(self.frame2, width=8, bg='white', fg='black', font=('Arial', 12))
self.f2e1.grid(row=1, column=1, pady=5)
self.f2l2 = tk.Label(self.frame2, text='Frame1 Entry2', font=('Arial', 12))
self.f2l2.grid(row=2, column=0, pady=5)
self.f2e2 = tk.Entry(self.frame2, width=8, bg='white', fg='black', font=('Arial', 12))
self.f2e2.grid(row=2, column=1, pady=5)
self.f2l3 = tk.Label(self.frame2, text='Frame1 Entry3', font=('Arial', 12))
self.f2l3.grid(row=3, column=0, pady=5)
self.f2e3 = tk.Entry(self.frame2, width=8, bg='white', fg='black', font=('Arial', 12))
self.f2e3.grid(row=3, column=1, pady=5)
self.f2e3.bind("<Tab> <FocusOut>", lambda refocus: self.f2e1.focus()) # 还有这里
self.root.mainloop()
if __name__ == '__main__':
Frame_Tab()
希望这对你有所帮助!
英文:
(this only works for versions 3.9 and below) I did that by simply binding last entry widgets by "Tab FocusOut". So if tab has been pressed and it focused out, you focus on the first entry widgets. So Just add that two lines:
self.f1e2.bind("<Tab> <FocusOut>", lambda refocus: self.f1e1.focus())
self.f2e3.bind("<Tab> <FocusOut>", lambda refocus: self.f2e1.focus())
Seems to work for me. Full code:
import tkinter as tk
class Frame_Tab:
def __init__(self):
self.root = tk.Tk()
self.root.geometry('300x350')
self.root.title('Frame Tab')
self.dg = '#c0c0c0'
self.bg = '#54ed58'
self.lg = '#c9c9c9'
self.frame1 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame1.pack()
self.f1heading = tk.Button(self.frame1,text='Frame 1',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,command=lambda:self.f1e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f1heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f1l1 = tk.Label(self.frame1,text='Frame1 Entry1',font=('Arial',12))
self.f1l1.grid(row=1,column=0,pady=5)
self.f1e1 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e1.grid(row=1,column=1,pady=5)
self.f1l2 = tk.Label(self.frame1,text='Frame1 Entry2',font=('Arial',12))
self.f1l2.grid(row=2,column=0,pady=5)
self.f1e2 = tk.Entry(self.frame1,width=8,bg='white',fg='black',font=('Arial',12))
self.f1e2.grid(row=2,column=1,pady=5)
self.f1e2.bind("<Tab> <FocusOut>", lambda refocus: self.f1e1.focus()) # there
self.frame2 = tk.LabelFrame(self.root,highlightcolor=self.bg,highlightthickness=3,highlightbackground=self.dg,padx=5,pady=5)
self.frame2.pack(pady=10)
self.f2heading = tk.Button(self.frame2,text='Frame 2',takefocus=0,bg=self.lg,fg='black',height=1,borderwidth=5,
command=lambda:self.f2e1.focus(), relief=tk.RAISED,font=('Arial',12))
self.f2heading.grid(row=0,column=0,columnspan=2,ipadx=10)
self.f2l1 = tk.Label(self.frame2,text='Frame1 Entry1',font=('Arial',12))
self.f2l1.grid(row=1,column=0,pady=5)
self.f2e1 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e1.grid(row=1,column=1,pady=5)
self.f2l2 = tk.Label(self.frame2,text='Frame1 Entry2',font=('Arial',12))
self.f2l2.grid(row=2,column=0,pady=5)
self.f2e2 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e2.grid(row=2,column=1,pady=5)
self.f2l3 = tk.Label(self.frame2,text='Frame1 Entry3',font=('Arial',12))
self.f2l3.grid(row=3,column=0,pady=5)
self.f2e3 = tk.Entry(self.frame2,width=8,bg='white',fg='black',font=('Arial',12))
self.f2e3.grid(row=3,column=1,pady=5)
self.f2e3.bind("<Tab> <FocusOut>", lambda refocus: self.f2e1.focus()) # and there
self.root.mainloop()
if __name__ == '__main__':
Frame_Tab()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论