官术网_书友最值得收藏!

Implementing the Find Text feature

Next, let's code the Find Text feature (2.05.py). The following screenshot shows an example of the Find Text feature:

Here's a quick summary of the desired functionality. When a user clicks on the Find menu item, a new Toplevel window opens up. The user enters a search keyword and specifies whether the search needs to be case-sensitive. When the user clicks on the Find All button, all matches are highlighted.

To search through the document, we rely on the text_widget.search() method. The search method takes in the following arguments:

search(pattern, startindex, stopindex=None, forwards=None, backwards=None, exact=None, regexp=None, nocase=None, count=None)

For the editor, define a function called find_text and attach it as a callback to the Find menu (2.05.py):

edit_menu.add_command(label='Find',underline= 0, accelerator='Ctrl+F', command=find_text)

Also, bind it to the Ctrl + F shortcut, as follows:

content_text.bind('<Control-f>', find_text)
content_text.bind('<Control-F>', find_text)

Then, define the find_text function, as follows (2.05.py):

def find_text(event=None):
search_toplevel = Toplevel(root)
search_toplevel.title('Find Text')
search_toplevel.transient(root)
Label(search_toplevel, text="Find All:").grid(row=0,
column=0,sticky='e')
search_entry_widget = Entry(search_toplevel, width=25)
search_entry_widget.grid(row=0, column=1, padx=2, pady=2,
sticky='we')
search_entry_widget.focus_set()
ignore_case_value = IntVar()
.... more code here to crate checkbox and button
def close_search_window():
content_text.tag_remove('match', '1.0', END)
search_toplevel.destroy()
search_toplevel.protocol('WM_DELETE_WINDOW',
close_search_window)
return "break"

The following is a description of the preceding code (2.05.py):

  • When a user clicks on the Find menu item, it invokes a find_text callback.
  •  The first four lines of the find_text() function create a new Toplevel window, add a window title, specify its geometry (size, shape, and location), and set it as a transient window. Setting it as a transient window means that it is always drawn on top of its parent or root window. If you comment out this line and click on the root editor window, the Find window will go behind the root window.
  • The next eight lines of code are pretty self-explanatory; they set the widgets of the Find window. They add the Label, Entry, Button, and Checkbutton widgets, and set up the search_string and ignore_case_value variables to track the value a user enters into the Entry widget and whether the user has checked off Checkbutton. The widgets are arranged by using the grid geometry manager to fit into the Find window.
  • The Find All button has a command option that calls a search_output function, passing the search string as the first argument and whether the search needs to be case-sensitive as its second argument. The third, fourth, and fifth arguments pass the Toplevel window, the Text widget, and the Entry widget as parameters.
  • We override the Close button of the Find window and redirect it to a callback named close_search(). The close_search function is defined within the find_text function. This function takes care of removing the match tag that was added during the search. If we do not override the Close button and remove these tags, the matched string will continue to be marked in red and yellow even after the search has ended.

Next, we define the search_output function, which does the actual searching and adds the match tag to the matching text. The code for this is as follows:

def search_output(needle, if_ignore_case, content_text,
search_toplevel, search_box):
content_text.tag_remove('match', '1.0', END)
matches_found = 0
if needle:
start_pos = '1.0'
while True:
start_pos = content_text.search(needle, start_pos,
nocase=if_ignore_case, stopindex=END)
if not start_pos:
break
end_pos = '{}+{}c'.format(start_pos, len(needle))
content_text.tag_add('match', start_pos, end_pos)
matches_found += 1
start_pos = end_pos
content_text.tag_config('match', foreground='red', background='yellow')
search_box.focus_set()
search_toplevel.title('{} matches found'.format(matches_found))

The following is a description of the preceding code:

  • This part of the code is the heart of the search function. It searches through the entire document by using the while True loop, breaking out of the loop only if no more text items remain to be searched.
  • The code first removes the previous search-related match tags if there are any, as we do not want to append the results of the new search to the previous search results. The function uses the search() method, which is provided in Tkinter in the Text widget. The search() method takes the following arguments:
      search(pattern, index, stopindex=None, forwards=None,
backwards=None, exact=None, regexp=None, nocase=None, count=None)
  • The search() method returns the starting position of the first match. We store it in a variable named start_pos, calculate the position of the last character in the matched word, and store it in the end_pos variable.
  • For every search match that it finds, it adds the match tag to the text ranging from the first position to the last position. After every match, we set the value of start_pos to be equal to end_pos. This ensures that the next search starts after end_pos.
  • The loop also keeps track of the number of matches by using the count variable.
  • Outside the loop, the tag match is configured to have a red font and yellow background. The last line of this function updates the title of the Find window with the number of matches that were found.
In case of event bindings, interaction occurs between input devices (keyboard/mouse) and your application. In addition to event binding, Tkinter also supports protocol handling.
The term protocol refers to the interaction between your application and the window manager. An example of a protocol is WM_DELETE_WINDOW, which handles the close window event for your window manager.
Tkinter lets you override these protocol handlers by mentioning your own handler for the root or Toplevel widget. To override the window exit protocol, we use the following command:
root.protocol(WM_DELETE_WINDOW, callback)
Once you add this command, Tkinter reroutes protocol handling to the specified callback/handler.
主站蜘蛛池模板: 隆回县| 甘洛县| 五家渠市| 桦甸市| 蕉岭县| 镇远县| 柳江县| 建宁县| 法库县| 天水市| 琼结县| 民权县| 柘荣县| 深州市| 饶平县| 开阳县| 宝兴县| 铅山县| 固安县| 通河县| 康保县| 临武县| 新巴尔虎右旗| 桦川县| 田林县| 保定市| 定陶县| 石屏县| 天津市| 葫芦岛市| 南澳县| 岑溪市| 丽江市| 白水县| 新竹县| 西畴县| 三台县| 冷水江市| 汶上县| 深圳市| 夏邑县|