Мне нужно получить только последний ввод из моего текстового виджета, а затем добавить этот символ в список.
я использую
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>'
Ни одна из этих попыток не работает. Я использовал оператор печати, чтобы увидеть, что представляют собой эти переменные при каждой итерации цикла, и, используя первый метод, он просто продолжает создавать все более и более длинные строки, которые постоянно повторяются, вместо обновления с каждым новым символом. Пытаясь другими способами, я просто ничего не получил, без вывода, но и без ошибки. Я полностью застрял и не знаю, что еще попробовать.
@BryanOakley, спасибо за комментарий, но я не очень понимаю, что вы говорите. Возможно, мой вопрос был немного непонятен. Я пытаюсь получить последний ввод, а затем добавить его в список, чтобы я мог сравнить его с моим целевым текстом на наличие ошибок. Я использовал ответ, представленный ниже, и по большей части он работает. Я надеюсь, что это прояснит проблему, с которой я столкнулся.
Допустим, пользователь вводит пять строк текста, и вы берете этот текст, чтобы выполнять любую обработку, которую хотите. Теперь, если пользователь щелкнет в верхней части виджета и вставит новую строку перед первой вместо того, чтобы печатать в конце, что вы ожидаете? Вы хотите получать только те новые символы, которые они ввели? Или все от начала, где они набрали, до конца?
@BryanOakley О, теперь я понимаю, что ты говоришь. Он должен получать только новые символы, а не весь текст в поле. Это тестовое приложение для набора текста, поэтому я просто не ожидал, что они щелкнут и начнут печатать в другом месте виджета.
Вы можете связать 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! Это работает очень хорошо, основываясь на печатном выводе, но я все еще получаю сумасшедшие цифры ошибок. Это из-за того, что пустая строка в начале списка меняет порядок сравнения, или я так вычисляю ошибки?
Вы неправильно вычисляете ошибки: каждый раз, когда вы выполняете итерацию в цикле while, вы снова считаете ошибки по всему списку. Вы можете попробовать добавить что-то вроде typed_text.pop(-1)
после оператора if.
Ой ну спасибо. Не знаю, как я это пропустил. Теперь я вычисляю как wpm, так и ошибки после разрыва цикла while. Я пробовал typed_text.pop(-1)
, typed_text.pop(0)
и typed_text.clear()
. Ни один из них не работал. Я не знаю, что вы подразумеваете под оператором if. Вы имеете в виду тот, который находится в цикле while или в цикле for? Потому что я переместил ошибки вычисления цикла for на более поздний уровень в программе, поэтому он не будет работать для этого. Теперь я думаю, что я вычисляю ошибки только один раз, что это проблема.
Не видя вашего кода, трудно получить правильный ответ, поэтому, если вам нужна дополнительная помощь, вы можете задать другой вопрос.
Текстовый виджет поддерживает то, что называется «меткой», похожей на закладку. Вы можете поставить отметку в любом месте текста и использовать ее так же, как обычный индекс.
Предполагая, что данные добавляются только в конец виджета, самое простое решение — получить блок данных, а затем переместить метку в конец извлеченного текста. В следующий раз, когда вы будете получать данные, начните с этой отметки.
У меток есть нечто, называемое «гравитацией», которое определяет, к какому символу прилипает метка. Например, если гравитация "левая" и вы установили ее на символ "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()
Добавляются ли данные только к виджету? Что, если пользователь вставит данные в начале виджета? Как вы ожидаете, что он будет вести себя в этом случае?