Tkinter文本查找窗口中‘上一个’按钮的实现难题
问题:Tkinter文本组件实现“上一个”查找按钮逻辑
我正在开发一款IDE,需要实现文本查找窗口,用于定位tkinter.text组件内的指定文本。目前“下一个”按钮功能已完成(可定位当前选中内容之后的匹配项),但无法实现“上一个”按钮逻辑——即定位当前选中内容之前的匹配项并设为新选中内容。
原相关代码
def find_function(event=None): global find_entry, idx, find_entry_stringvar idx = "1.0" find_window = tkinter.Toplevel(editing_area) def callback(var): global idx, find_entry_stringvar idx = "1.0" find_entry_stringvar = var.get() find_entry_stringvar.trace_add("write", lambda name, index, mode, find_entry_stringvar=find_entry_stringvar: callback(find_entry_stringvar)) find_entry = tkinter.Entry(find_window, width=24, textvariable=find_entry_stringvar) def check_focus(event=None): editing_area.tag_remove("found", "1.0", "end") editing_area.bind("<FocusIn>", check_focus) find_window.bind("<FocusOut>", check_focus) find_entry.pack() find_entry.focus_force() previous_button = tkinter.Button(find_window, text="←", border=1, fg="white", bg="black", command=lambda: find_buttons_function(previous_or_next="previous")) previous_button.pack(side="left") find_window.bind("<Shift-Return>", lambda: find_buttons_function(previous_or_next="previous")) next_button = tkinter.Button(find_window, text="→", border=1, fg="white", bg="black", command=lambda: find_buttons_function(previous_or_next="next")) next_button.pack(side="right") find_window.bind("<Return>", lambda: find_buttons_function(previous_or_next="next")) def find_buttons_function(previous_or_next, event=None): global find_entry, idx, find_matches_found, find_to_find editing_area.tag_remove("found", "1.0", "end") find_to_find = find_entry_stringvar no_of_finds = 0 if find_to_find: if previous_or_next == "previous": pass elif previous_or_next == "next": match_in_whole_text = editing_area.search(find_to_find, "1.0", "end") if match_in_whole_text: find_matches_found = True else: find_matches_found = False idx = editing_area.search(find_to_find, idx, "end") if idx: lastidx = f"{idx}+{len(find_to_find)}c" editing_area.tag_add("found", idx, lastidx) editing_area.tag_config("found", background="#8fa7cc") editing_area.see(idx) idx = lastidx editing_area.mark_set("insert", idx) else: if find_matches_found == False: tkinter.messagebox.showerror("No match found", f"No match for {find_to_find} was found") else: idx = "1.0" find_buttons_function(previous_or_next="next")
尝试的“上一个”按钮逻辑
if previous_or_next == "previous": i = 0 match_in_whole_text = editing_area.search(find_to_find, "1.0", "end") if match_in_whole_text: find_matches_found = True else: find_matches_found = False idx = editing_area.search(find_to_find, "1.0", "end") lastidx = f"{idx}+{len(find_to_find)}c" if idx: while idx: lastidx = f"{idx}+{len(find_to_find)}c" idx = editing_area.search(find_to_find, lastidx, "end") no_of_finds += 1 idx = editing_area.search(find_to_find, "1.0", "end") lastidx = f"{idx}+{len(find_to_find)}c" while i < no_of_finds - 1: lastidx = f"{idx}+{len(find_to_find)}c" idx = editing_area.search(find_to_find, lastidx, "end") i += 1 lastidx = f"{idx}+{len(find_to_find)}c" editing_area.tag_add("found", idx, lastidx) editing_area.tag_config("found", background="#8fa7cc") editing_area.see(idx) editing_area.mark_set("insert", idx) else: if find_matches_found == False: tkinter.messagebox.showerror("No match found", f"No match for {find_to_find} was found")
解决方案
核心思路
Tkinter的Text.search()方法支持反向查找,通过设置backwards=True参数可以直接从当前位置向前搜索匹配项,无需遍历所有匹配项,同时处理循环查找逻辑(当到达文档开头时,跳转到末尾继续查找)。
修改后的完整find_buttons_function
def find_buttons_function(previous_or_next, event=None): global find_entry, idx, find_matches_found, find_to_find editing_area.tag_remove("found", "1.0", "end") # 修正:获取输入框内容需要调用get()方法 find_to_find = find_entry_stringvar.get() if find_to_find: # 检查整个文档是否存在匹配项,用于循环查找的判断 match_in_whole_text = editing_area.search(find_to_find, "1.0", "end") find_matches_found = bool(match_in_whole_text) if previous_or_next == "previous": # 反向查找:从当前位置的前一个字符开始,向文档开头搜索 search_start = f"{idx}-1c" if idx != "1.0" else idx idx = editing_area.search(find_to_find, search_start, "1.0", backwards=True) if idx: lastidx = f"{idx}+{len(find_to_find)}c" editing_area.tag_add("found", idx, lastidx) editing_area.tag_config("found", background="#8fa7cc") editing_area.see(idx) idx = lastidx editing_area.mark_set("insert", idx) else: if not find_matches_found: tkinter.messagebox.showerror("No match found", f"No match for {find_to_find} was found") else: # 循环到文档末尾,查找最后一个匹配项 idx = "end" find_buttons_function(previous_or_next="previous") elif previous_or_next == "next": idx = editing_area.search(find_to_find, idx, "end") if idx: lastidx = f"{idx}+{len(find_to_find)}c" editing_area.tag_add("found", idx, lastidx) editing_area.tag_config("found", background="#8fa7cc") editing_area.see(idx) idx = lastidx editing_area.mark_set("insert", idx) else: if not find_matches_found: tkinter.messagebox.showerror("No match found", f"No match for {find_to_find} was found") else: idx = "1.0" find_buttons_function(previous_or_next="next")
关键修改点
- 反向查找参数:使用
backwards=True实现从当前位置向前搜索,简化逻辑 - 输入内容获取:修正
find_to_find的赋值,调用find_entry_stringvar.get()获取输入框实际内容 - 搜索起始位置:反向查找时从当前
idx的前一个字符开始,避免重复选中当前匹配项 - 循环查找处理:当搜索到文档开头无匹配时,自动跳转到文档末尾继续查找,实现循环遍历
内容的提问来源于stack exchange,提问作者Swagrim
相关产品推荐
相关产品推荐

