Примените IntVar () к сосредоточенному Entry () tkinter - PullRequest
0 голосов
/ 30 января 2019

У меня есть приложение 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 в зависимости от того, какая из них имеет фокус.

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Если я правильно понял вопрос, все, что вы на самом деле спрашиваете, - как кнопка должна знать, куда вставить текст.Я не думаю, что использование IntVar действительно имеет к этому какое-то отношение, это проблема xy .Вы можете использовать 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] (с акцентом на минимум ), поскольку нам трудно сосредоточиться только на задаваемом вопросе.Другой код скрывает проблему.

Короткое исправление, позволяющее вам знать, что это решение работает, - временно отключить проверку ввода.

Кроме того, это решение предполагает, что вы нажали одну из записей, прежде чем нажатькнопка.Вы можете обойти это, вызвав self.user_number_entry.focus_set() в вашем __init__, что заставит фокус ввода начинаться с этого виджета ввода.

0 голосов
/ 30 января 2019

Вы можете добавить привязку к событию "<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, если пользователь изменит фокус записи, и, как мне кажется, это нежелательное поведение.

...