tkinter回车自动切换焦点

一个用户小需求,要求在输入了账号和密码后按回车能够自动切换焦点,当焦点在button上时按回车和点击效果一样,一句话就是不想用鼠标。

功能很好实现,每个entry绑定回车再转移焦点即可,但如果输入的项目比较多,代码冗长就让人讨厌了,能不能从底层去解决?

百度几番找到一段代码,通过继承entry,绑定回车实现焦点的自动后移,效果不错,代码精炼!


import tkinter as tk

class MyEntry(tk.Entry):
    """Entry widget with Return bound to provide tabbing functionality"""
    def __init__(self, master, **kw):
        tk.Entry.__init__(self, master, **kw)
        self.next_widget = None
        self.bind("<Return>", self.on_ret)
    def on_ret(self, ev):
        if self.next_widget:
            self.event_generate('<<TraverseOut>>')
            self.next_widget.focus()
            self.next_widget.event_generate('<<TraverseIn>>')
        else:
            self.event_generate('<<NextWindow>>')
        return "break"
    def set_next(self, widget):
        """Override the default next widget for this instance"""
        self.next_widget = widget

def add_entry(parent, row, **kwargs):
    widget = MyEntry(parent, **kwargs)
    widget.grid(row=row, column=0, sticky=tk.NSEW)
    return widget

def main(args=None):
    root = tk.Tk()

    frame = tk.LabelFrame(root, text="Entries", width=200, height=200)

    entries = []
    for row in range(4):
        e = add_entry(frame, row)
        entries.append(e)
    e.set_next(entries[0])

    frame.grid_columnconfigure(0, weight=1)
    frame.grid_rowconfigure(0, weight=0)

    button = tk.Button(root, text="Exit", command=root.destroy)

    frame.grid(row=0, column=0, sticky=tk.NSEW)
    button.grid(row=1, column=0, sticky=tk.SE)
    root.grid_columnconfigure(0, weight=1)
    root.grid_rowconfigure(0, weight=1)

    entries[0].focus_set()
    root.mainloop()

if __name__ == '__main__':
    main()

美中不足,这段代码写死了Entry!我还有几个Button也要获得焦点,还有其它类似的控制,最好能有个完美的“中间层”实现焦点控制。

借鉴上段代码,利用python OO多继承的特点构造了一个中间控制。

MYCtrl实现控件收到回车事件后需要判断的逻辑,这里面再判断是何种类型的控件,去实现相应动作,button执行创建时传入的command,entry则焦点转换到下一个控件

class MyCtrl:
    def on_ret(self, ev):
        if self.widgetName == "button":
            self.invoke()
        elif self.widgetName == "entry":
            if self.next_widget:
                self.event_generate('<<TraverseOut>>')
                self.next_widget.focus()
                self.next_widget.event_generate('<<TraverseIn>>')
            else:
                self.event_generate('<<NextWindow>>')
        return "break"
    def set_next(self, widget):
        """Override the default next widget for this instance"""
        self.next_widget = widget

用Entry,Button分别和MyCtrl派生新控件,在类的init方法中绑定回车键的相应,即与MYCtrl.on_ret捆绑中一起,至此焦点自动转移需求完美实现!

class MyEntry(tk.Entry,MyCtrl):
    def __init__(self, master, **kw):
        tk.Entry.__init__(self, master, **kw)
        
        self.next_widget = None
        self.bind("<Return>", self.on_ret)

class MyButton(tk.Button,MyCtrl):
    def __init__(self, master, **kw):
        tk.Button.__init__(self, master, **kw)
        
        self.next_widget = None
        self.bind("<Return>", self.on_ret)    

完整代码如下:

import tkinter as tk

class MyCtrl:
    def on_ret(self, ev):
        if self.widgetName == "button":
            self.invoke()
        elif self.widgetName == "entry":
            if self.next_widget:
                self.event_generate('<<TraverseOut>>')
                self.next_widget.focus()
                self.next_widget.event_generate('<<TraverseIn>>')
            else:
                self.event_generate('<<NextWindow>>')
        return "break"
    def set_next(self, widget):
        """Override the default next widget for this instance"""
        self.next_widget = widget

class MyEntry(tk.Entry,MyCtrl):
    def __init__(self, master, **kw):
        tk.Entry.__init__(self, master, **kw)
        
        self.next_widget = None
        self.bind("<Return>", self.on_ret)

class MyButton(tk.Button,MyCtrl):
    def __init__(self, master, **kw):
        tk.Button.__init__(self, master, **kw)
        
        self.next_widget = None
        self.bind("<Return>", self.on_ret)    

def add_entry(parent, row, **kwargs):
    widget = MyEntry(parent, **kwargs)
    widget.grid(row=row, column=0, sticky=tk.NSEW)
    return widget

def main(args=None):
    root = tk.Tk()
    root.title("回车自动转移焦点、触发button")

    frame = tk.LabelFrame(root, text="Entries", width=200, height=200)

    entries = []
    for row in range(5):
        e = add_entry(frame, row)
        entries.append(e)
    # e.set_next(entries[0])

    frame.grid_columnconfigure(0, weight=1)
    frame.grid_rowconfigure(0, weight=0)

    button = MyButton(root, text="Exit", command=root.destroy)

    frame.grid(row=0, column=0, sticky=tk.NSEW)
    button.grid(row=1, column=0, sticky=tk.SE)
    root.grid_columnconfigure(0, weight=1)
    root.grid_rowconfigure(0, weight=1)

    entries[0].focus_set()
    root.mainloop()

if __name__ == '__main__':
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值