Как получить только последний ввод из текстового виджета tkinter?

Мне нужно получить только последний ввод из моего текстового виджета, а затем добавить этот символ в список. я использую Text.get(1.0,'end-1c') , и это не работает, потому что цикл постоянно получает все входные данные, а не получает последние входные данные только при наличии новых последних входных данных.

def main_screen():
    start_time=time.time()
    tk=Tk()
    tk.title('Typing Test')
    tk.geometry('800x500')
    main_title=Label(tk,text='1 Minute Test',font=('Times New Roman',36))
    main_title.pack(pady=5)
    directions=Label(tk,text='Start Typing',font=('Times New Roman',14))
    directions.pack()
    base_text=Label(tk,text=randomizer(),bg='#E0E0EE',font=('Arial',14),wraplength=700,justify=LEFT)
    base_text.pack(pady=10)
    text_area=Text(tk,font=('Arial',14),width=63,height=7,wrap='word')
    text_area.pack()
    tk.update()
#WPM Calculation
    target_text=randomizer()
    typed_text=[]
    wpm=0
    errors=0
    while True:
        tk.update()
        time_elapsed=max(time.time()-start_time,1)
        wpm=round((len(typed_text)/60)/5)
        if time_elapsed>=60:
            break
#Problem Section
        key=text_area.get(1.0,'end-1c')
        typed_text.append(key)
        for x in typed_text:
            if x != target_text:
                errors += 1

В качестве альтернативы я попытался использовать переменную вместо 1.0 в .get, которая будет увеличиваться на единицу с каждой итерацией цикла. Затем я попробовал команду try/except и поместил раздел #Problem в функцию. Я попытался вызвать эту функцию, привязав текстовую область к

'<Key>'
'<KeyPress>'
'<KeyRelease>'

Ни одна из этих попыток не работает. Я использовал оператор печати, чтобы увидеть, что представляют собой эти переменные при каждой итерации цикла, и, используя первый метод, он просто продолжает создавать все более и более длинные строки, которые постоянно повторяются, вместо обновления с каждым новым символом. Пытаясь другими способами, я просто ничего не получил, без вывода, но и без ошибки. Я полностью застрял и не знаю, что еще попробовать.

Добавляются ли данные только к виджету? Что, если пользователь вставит данные в начале виджета? Как вы ожидаете, что он будет вести себя в этом случае?

Bryan Oakley 10.11.2022 17:01

@BryanOakley, спасибо за комментарий, но я не очень понимаю, что вы говорите. Возможно, мой вопрос был немного непонятен. Я пытаюсь получить последний ввод, а затем добавить его в список, чтобы я мог сравнить его с моим целевым текстом на наличие ошибок. Я использовал ответ, представленный ниже, и по большей части он работает. Я надеюсь, что это прояснит проблему, с которой я столкнулся.

Thomas 10.11.2022 17:57

Допустим, пользователь вводит пять строк текста, и вы берете этот текст, чтобы выполнять любую обработку, которую хотите. Теперь, если пользователь щелкнет в верхней части виджета и вставит новую строку перед первой вместо того, чтобы печатать в конце, что вы ожидаете? Вы хотите получать только те новые символы, которые они ввели? Или все от начала, где они набрали, до конца?

Bryan Oakley 10.11.2022 18:28

@BryanOakley О, теперь я понимаю, что ты говоришь. Он должен получать только новые символы, а не весь текст в поле. Это тестовое приложение для набора текста, поэтому я просто не ожидал, что они щелкнут и начнут печатать в другом месте виджета.

Thomas 10.11.2022 20:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете связать text_area с событием <KeyPress>, но вам нужно передать список typed_text в качестве аргумента, чтобы вы могли добавлять нажатия.

Итак, вы должны сделать что-то вроде этого:

text_area.bind("<KeyPress>", lambda _: getKey(_, typed_text))
    while True:
        tk.update()
        time_elapsed = max(time.time() - start_time, 1)
        wpm = round((len(typed_text) / 60) / 5)
        if time_elapsed >= 60:
            break
        # Problem Section
        for x in typed_text:
            if x != target_text:
                errors += 1


def getKey(event, list):
    list.append(event.char)
    print(list)

Спасибо @DonPre! Это работает очень хорошо, основываясь на печатном выводе, но я все еще получаю сумасшедшие цифры ошибок. Это из-за того, что пустая строка в начале списка меняет порядок сравнения, или я так вычисляю ошибки?

Thomas 10.11.2022 17:53

Вы неправильно вычисляете ошибки: каждый раз, когда вы выполняете итерацию в цикле while, вы снова считаете ошибки по всему списку. Вы можете попробовать добавить что-то вроде typed_text.pop(-1) после оператора if.

DonPre 10.11.2022 17:54

Ой ну спасибо. Не знаю, как я это пропустил. Теперь я вычисляю как wpm, так и ошибки после разрыва цикла while. Я пробовал typed_text.pop(-1), typed_text.pop(0) и typed_text.clear(). Ни один из них не работал. Я не знаю, что вы подразумеваете под оператором if. Вы имеете в виду тот, который находится в цикле while или в цикле for? Потому что я переместил ошибки вычисления цикла for на более поздний уровень в программе, поэтому он не будет работать для этого. Теперь я думаю, что я вычисляю ошибки только один раз, что это проблема.

Thomas 10.11.2022 20:11

Не видя вашего кода, трудно получить правильный ответ, поэтому, если вам нужна дополнительная помощь, вы можете задать другой вопрос.

DonPre 11.11.2022 08:34

Текстовый виджет поддерживает то, что называется «меткой», похожей на закладку. Вы можете поставить отметку в любом месте текста и использовать ее так же, как обычный индекс.

Предполагая, что данные добавляются только в конец виджета, самое простое решение — получить блок данных, а затем переместить метку в конец извлеченного текста. В следующий раз, когда вы будете получать данные, начните с этой отметки.

У меток есть нечто, называемое «гравитацией», которое определяет, к какому символу прилипает метка. Например, если гравитация "левая" и вы установили ее на символ "2.2", метка всегда будет оставаться рядом с символом с индексом "2.2". Если гравитация «правильная», она застрянет на символе, следующем за индексом «2.2» (например: «2.3» или «3.0»).

Вот надуманный пример, который будет печатать только последние добавления к текстовому виджету каждые пять секунд, отслеживая последнюю позицию, которая использовалась для выборки данных.

import tkinter as tk

def get_new_text():
    data = text.get("last", "end-1c")
    print(f"new data: >>>{data}<<<")
    text.mark_set("last", "end-1c")
    root.after(5000, get_new_text)

root = tk.Tk()
text = tk.Text(root, wrap = "word")
text.pack(fill = "both", expand=True)
text.mark_set("last", "1.0")
text.mark_gravity("last", "left")

root.after(5000, get_new_text)

root.mainloop()

Другие вопросы по теме