将IntVar()应用于专注的Entry()tkinter

时间:2019-01-30 08:53:16

标签: tkinter python-2.x

我有一个tkinter应用程序,其中有2个输入框和带有数字0-9的按钮。我希望能够使用按钮输入IntVar(),但可以将焦点输入到Entry()中。此刻,我可以按下按钮以将IntVar()输入到第一个Entry()框中,但是我无法弄清楚或无法在线找到如何仅将IntVar()输入到焦点突出的{{ 1}}框。

Entry()

我需要使用按钮将数字输入import sys from tkinter import Tk, Text, BOTH, W, N, E, S, IntVar from tkinter.ttk import Frame, Button, Label, Style, Entry expression = '' class Example(Frame): def __init__(self, *args, **kwargs): Frame.__init__(self, *args, **kwargs) self.name = 'Application' self.master.title(self.name) self.pack(fill=BOTH, expand=True) cancel_btn_style = Style() cancel_btn_style.configure('CNL.TButton', background='red') cancel_btn_style = Style() cancel_btn_style.configure('LGN.TButton', background='green') self.columnconfigure(1, weight=1) self.columnconfigure(2, weight=1) self.columnconfigure(3, weight=1) self.rowconfigure(0, weight=1) self.rowconfigure(1, weight=1) self.rowconfigure(2, weight=1) self.rowconfigure(3, weight=1) self.rowconfigure(4, weight=1) self.rowconfigure(5, weight=1) self.user_number_var = IntVar() self.main_label = Label(self, text=self.name) self.main_label.grid(sticky=W, pady=4, padx=5) self.entry_label = Label(self, text='User Number / PIN') self.entry_label.grid( row=1, column=0, columnspan=1, rowspan=1, padx=5, sticky=E+W+S+N ) vcmd = (self.register(self.__vcmd), '%P') self.user_number_entry = Entry( self, validate='key', validatecommand=vcmd, textvariable=self.user_number_var ) self.user_number_entry.grid( row=1, column=1, columnspan=1, rowspan=1, sticky=N+S+E+W, pady=4 ) self.pin_number_entry = Entry(self, validate='key', validatecommand=vcmd, show='*') self.pin_number_entry.grid( row=1, column=2, columnspan=1, rowspan=1, sticky=N+S+E+W, pady=4 ) self.btn_1 = Button(self, text='1', command=lambda: self.press(1)) self.btn_1.grid(row=2, column=0, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_2 = Button(self, text='2', command=lambda: self.press(2)) self.btn_2.grid(row=2, column=1, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_3 = Button(self, text='3', command=lambda: self.press(3)) self.btn_3.grid(row=2, column=2, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_4 = Button(self, text='4', command=lambda: self.press(4)) self.btn_4.grid(row=3, column=0, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_5 = Button(self, text='5', command=lambda: self.press(5)) self.btn_5.grid(row=3, column=1, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_6 = Button(self, text='6', command=lambda: self.press(6)) self.btn_6.grid(row=3, column=2, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_7 = Button(self, text='7', command=lambda: self.press(7)) self.btn_7.grid(row=4, column=0, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_8 = Button(self, text='8', command=lambda: self.press(8)) self.btn_8.grid(row=4, column=1, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_9 = Button(self, text='9', command=lambda: self.press(9)) self.btn_9.grid(row=4, column=2, columnspan=1, rowspan=1, sticky=N+S+E+W) self.cancel_btn = Button(self, text='Cancel / Close', command=sys.exit, style='CNL.TButton') self.cancel_btn.grid(row=5, column=0, columnspan=1, rowspan=1, sticky=N+S+E+W) self.btn_0 = Button(self, text='0', command=lambda: self.press(0)) self.btn_0.grid(row=5, column=1, columnspan=1, rowspan=1, sticky=N+S+E+W) self.login_btn = Button(self, text='Log In', style='LGN.TButton') self.login_btn.grid(row=5, column=2, columnspan=1, rowspan=1, sticky=N+S+E+W) def press(self, num): # point out the global expression variable global expression # concatenation of string expression = expression + str(num) # update the expression by using set method self.user_number_var.set(expression) def __vcmd(self, P, S): print('__vcmd') def main(): root = Tk() root.geometry('540x640') app = Example(root) root.mainloop() if __name__ == '__main__': main() self.user_number_entry中,具体取决于哪个焦点。

2 个答案:

答案 0 :(得分:1)

您可以将绑定添加到"<FocusIn>"事件中,以检查焦点集中在哪个条目上,并检查insert的值:

....

def __init__(self, *args, **kwargs):
    ....
    self.user_number_var = IntVar()
    self.pin_number_var = IntVar()
    self.user_number_entry = Entry(
        self, validate='key', validatecommand=vcmd, 
        textvariable=self.user_number_var
    )
    self.user_number_entry.grid(
        row=1, column=1, columnspan=1, 
        rowspan=1, sticky=N+S+E+W, pady=4
    )
    self.user_number_entry.bind("<FocusIn>", self.remember_focus)

    self.pin_number_entry = Entry(self, textvariable=self.pin_number_var, validate='key', validatecommand=vcmd, show='*')
    self.pin_number_entry.grid(
        row=1, column=2, columnspan=1, 
        rowspan=1, sticky=N+S+E+W, pady=4
    )
    self.pin_number_entry.bind("<FocusIn>", self.remember_focus)
    ....

def remember_focus(self,event):
    global focused_entry
    focused_entry = event.widget    

def press(self, num):
    focused_entry.insert('end',str(num))

如果您坚持使用IntVar()的另一种解决方案是将bind的各个功能分别entry,然后将global variable设置为焦点的IntVar(),允许你然后输入你的表达到在焦点条目的IntVar()

...
def __init__(self, *args, **kwargs):
    self.user_number_var = IntVar()
    self.pin_number_var = IntVar()

    self.main_label = Label(self, text=self.name)
    self.main_label.grid(sticky=W, pady=4, padx=5)

    self.entry_label = Label(self, text='User Number / PIN')
    self.entry_label.grid(
        row=1, column=0, columnspan=1,
        rowspan=1, padx=5, sticky=E+W+S+N
    )

    self.user_number_entry = Entry(
        self, validate='key', validatecommand=vcmd, 
        textvariable=self.user_number_var
    )
    self.user_number_entry.grid(
        row=1, column=1, columnspan=1, 
        rowspan=1, sticky=N+S+E+W, pady=4
    )
    self.user_number_entry.bind("<FocusIn>", self.set_user_number_int_var)

    self.pin_number_entry = Entry(self, textvariable=self.pin_number_var, validate='key', validatecommand=vcmd, show='*')
    self.pin_number_entry.grid(
        row=1, column=2, columnspan=1, 
        rowspan=1, sticky=N+S+E+W, pady=4
    )
    self.pin_number_entry.bind("<FocusIn>", self.set_pin_number_int_var)
...

def set_user_number_int_var(self,event):
    global set_int_var
    set_int_var = self.user_number_var

def set_pin_number_int_var(self,event):
    global set_int_var
    set_int_var = self.pin_number_var        


def press(self, num):
    # point out the global expression variable
    global expression,set_int_var

    # concatenation of string
    expression = expression + str(num)
    set_int_var.set(expression)

一个缩回:串联:

 expression = expression + str(num)

如果用户更改条目的焦点,并且我认为这不是期望的行为,这将继承expression中已经存在的所有内容。

答案 1 :(得分:1)

如果我理解正确的问题,那么您真正要问的是按钮应该如何知道在何处插入文本。我认为IntVar的使用与它无关,而是xy problem。您可以根据需要使用IntVar,但它们与此问题无关。

Tkinter提供了一个命令来获取当前关注的窗口小部件-focus_get。单击按钮时,可以将文本插入该小部件的末尾。您无需使用IntVar

但是,您使用的是ttk按钮,它们会占用焦点。对于ttk开发人员而言,这是一个错误的设计决策,但这是没有意义的。最简单的解决方案是跟踪哪个条目小部件上次获得焦点。然后,您可以将数字直接添加到输入小部件中。

首先在每个条目小部件上添加一个绑定,以在其获得焦点时记住自己。创建条目后的某个时间,可以使用与创建条目相同的方法来执行此操作:

self.user_number_entry.bind("<FocusIn>", self._remember_focus)
self.pin_number_entry.bind("<FocusIn>", self._remember_focus)

接下来,我们需要定义_remember_focus方法以记住上一个焦点所在的小部件:

def _remember_focus(self, event):
    self._current_entry = event.widget

最后,我们需要修改press命令以将数字直接附加到条目小部件中。在此示例中,我还将焦点重置为条目小部件。我不确定您是否想要。

def press(self, num):
    self._current_entry.insert("end", str(num))
    self._current_entry.focus_set()

注意:您的代码中还有其他错误将阻止此错误的发生。具体来说,您的输入验证代码中有错误。这就是为什么我们要求一个[mcve](以 minimum 为重点)的原因,因为这使我们很难仅专注于所问的问题。其他代码遮盖了问题。

一个简短的解决方法是暂时关闭您的输入验证,以便您知道此解决方案正在工作。

此外,此解决方案假定您在单击按钮之前已单击其中一项。您可以通过在self.user_number_entry.focus_set()中调用__init__来解决此问题,这将迫使输入焦点从该输入小部件开始。