将 IntVar() 应用于重点 Entry() tkinter
Apply IntVar() to focused Entry() tkinter
我有一个 tkinter 应用程序,它有 2 个输入框和带有数字 0-9 的按钮。我希望能够使用按钮输入 IntVar()
,但进入焦点 Entry()
。目前我可以按下按钮将 IntVar()
输入到第一个 Entry()
框中,但我无法弄清楚或无法在网上找到如何仅将 IntVar()
输入焦点 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
或 self.pin_number_entry
中,具体取决于哪一个具有焦点。
您可以将绑定添加到 "<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
中已有的任何内容,我想这不是期望的行为。
如果我对问题的理解是正确的,那么您真正想问的是按钮应该如何知道在何处插入文本。我不认为 IntVar
的使用真的与它有任何关系,那是 xy problem。如果您愿意,可以使用 IntVar
s,但它们与此问题无关。
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),因为它让我们很难只关注被问到的问题。其他代码掩盖了这个问题。
让您知道此解决方案有效的一个简短修复是暂时关闭您的输入验证。
此外,此解决方案假定您在单击按钮之前已单击其中一个条目。您可以通过在 __init__
中调用 self.user_number_entry.focus_set()
来解决这个问题,这将强制输入焦点从该条目小部件开始。
我有一个 tkinter 应用程序,它有 2 个输入框和带有数字 0-9 的按钮。我希望能够使用按钮输入 IntVar()
,但进入焦点 Entry()
。目前我可以按下按钮将 IntVar()
输入到第一个 Entry()
框中,但我无法弄清楚或无法在网上找到如何仅将 IntVar()
输入焦点 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
或 self.pin_number_entry
中,具体取决于哪一个具有焦点。
您可以将绑定添加到 "<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
中已有的任何内容,我想这不是期望的行为。
如果我对问题的理解是正确的,那么您真正想问的是按钮应该如何知道在何处插入文本。我不认为 IntVar
的使用真的与它有任何关系,那是 xy problem。如果您愿意,可以使用 IntVar
s,但它们与此问题无关。
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),因为它让我们很难只关注被问到的问题。其他代码掩盖了这个问题。
让您知道此解决方案有效的一个简短修复是暂时关闭您的输入验证。
此外,此解决方案假定您在单击按钮之前已单击其中一个条目。您可以通过在 __init__
中调用 self.user_number_entry.focus_set()
来解决这个问题,这将强制输入焦点从该条目小部件开始。