首页 > 解决方案 > 将 IntVar() 应用于重点 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_entryself.pin_number_entry取决于哪个有焦点。

标签: tkinterpython-2.x

解决方案


如果我正确理解了这个问题,那么您真正要问的是按钮应该如何知道在哪里插入文本。我认为使用IntVar与它没有任何关系,这是一个xy 问题。如果您愿意,您可以使用IntVars,但它们与此问题无关。

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__,这将强制输入焦点从该条目小部件开始。


推荐阅读