简体   繁体   English

如何在 tkinter Text 小部件中实现查找和替换功能?

[英]How do I implement a find and replace function in a tkinter Text widget?

I have the following code:我有以下代码:

def find_and_replace(self, *args):

        findandreplace = tk.Toplevel(master)
        findandreplace.title('Find & Replace')

        find_label = tk.Label(findandreplace, text='Find')
        find_label.pack(side = tk.LEFT) 
        find_words = tk.StringVar()
        find_entry = tk.Entry(findandreplace, textvariable=find_words)
        find_entry.pack(side = tk.LEFT, fill = tk.BOTH, expand = 1)

        find_button = tk.Button(findandreplace, text='Find', command=self.find)
        find_button.pack(side = tk.LEFT)

        replace_label = tk.Label(findandreplace, text='Replace')
        replace_label.pack(side = tk.LEFT) 
        replace_words = tk.StringVar()
        replace_entry = tk.Entry(findandreplace, textvariable=replace_words)
        replace_entry.pack(side = tk.LEFT, fill = tk.BOTH, expand = 1)
        
        replace_button = tk.Button(findandreplace, text='Replace', command=self.replace)
        replace_button.pack(side = tk.LEFT)

        find_string = find_words.get()
        replace_string = replace_words.get()

        return find_string, replace_string

    
    def find(self, *args):
        self.textarea.tag_remove('found', '1.0', tk.END)
        find_word = self.find_and_replace()[0]
        if find_word:
            idx = '1.0'
            while True:
                idx = self.textarea.search(find_word, idx, nocase=1,
                                            stopindex=tk.END)

                if not idx:
                    break

                lastidx = '% s+% dc' % (idx, len(find_word))
                idx = lastidx
            self.textarea.tag_config('found', foreground='red')
    
    def replace(self, *args):
        self.textarea.tag_remove('found', '1.0', tk.END)
        find_word = self.find_and_replace()[0]
        replace_word = self.find_and_replace()[1]

        if find_word and replace_word:
            idx = '1.0'
            while True:
                idx = self.textarea.search(find_word, idx, nocase=1,
                                            stopindex=tk.END)
                if not idx:
                    break

                lastidx = '% s+% dc' % (idx, len(find_word))
                self.textarea.delete(idx, lastidx)
                self.textarea.insert(idx, replace_word)

                lastidx = '% s+% dc' % (idx, len(replace_word))
                idx = lastidx
            self.textarea.tag_config('found', foreground='green', background='yellow')

And I am using a menubar in a different class to access this:我正在使用不同类中的菜单栏来访问它:

edit_dropdown.add_command(label="Find",
                          command=parent.find)     
edit_dropdown.add_command(label="Replace",
                          command=parent.find_and_replace)

So, find_and_replace() creates a new tk.Toplevel widget where I can access the find() and replace() functions.因此, find_and_replace()创建了一个新的tk.Toplevel小部件,我可以在其中访问find()replace()函数。

However, when I press on the respective buttons, all I get is two more windows created.但是,当我按下相应的按钮时,我得到的只是创建了两个窗口。 I want to highlight the find_words string and then have it replaced by the replace_words string.我想突出显示find_words字符串,然后将其替换为replace_words字符串。

I feel I'm messing up by accessing variables of one method in another and in the opposite manner.我觉得我通过以另一种方式以相反的方式访问一种方法的变量而搞砸了。

The root of your problem are these lines:你的问题的根源是这些行:

find_word = self.find_and_replace()[0]
replace_word = self.find_and_replace()[1]

self.find_and_replace creates the dialog. self.find_and_replace创建对话框。 You don't want to be creating new dialogs.您不想创建新对话框。 Instead, you need to access the widgets in the current dialog.相反,您需要访问当前对话框中的小部件。 That means you need to save references to the widgets as instance attributes, and then use those instance attributes.这意味着您需要将小部件的引用保存为实例属性,然后使用这些实例属性。

Note: you can reduce the complexity by not using the textvariable attribute.注意:您可以通过使用textvariable属性来降低复杂性。 You're just adding overhead since you aren't taking advantage of any features of the variable that you can't do by just calling the entry widget directly您只是增加了开销,因为您没有利用直接调用条目小部件无法实现的变量的任何功能

For example:例如:

def find_and_replace(self, *args):
    ...
    self.find_entry = tk.Entry(findandreplace)
    self.replace_entry = tk.Entry(findandreplace)
    ...

def replace(self, *args):
    ...
    find_word = self.find_entry.get()
    replace_word = self.replace_entry.get()
    ...

Something like this should do the trick:像这样的事情应该可以解决问题:

from tkinter import *
  
  
# to create a window  
root = Tk()  
  
# root window is the parent window  
fram = Frame(root)  
  
# Creating Label, Entry Box, Button  
# and packing them adding label to 
# search box  
Label(fram, text ='Find').pack(side = LEFT) 
  
# adding of single line text box  
edit = Entry(fram)  
  
# positioning of text box  
edit.pack(side = LEFT, fill = BOTH, expand = 1)  
  
# setting focus  
edit.focus_set()  
  
# adding of search button  
Find = Button(fram, text ='Find') 
Find.pack(side = LEFT) 
  
  
Label(fram, text = "Replace With ").pack(side = LEFT) 
  
edit2 = Entry(fram) 
edit2.pack(side = LEFT, fill = BOTH, expand = 1) 
edit2.focus_set() 
  
replace = Button(fram, text = 'FindNReplace') 
replace.pack(side = LEFT) 
  
fram.pack(side = TOP)  
  
# text box in root window  
text = Text(root)  
  
# text input area at index 1 in text window  
text.insert('1.0', '''Type your text here''')  
text.pack(side = BOTTOM)  
  
# function to search string in text  
def find():  
    # remove tag 'found' from index 1 to END  
    text.tag_remove('found', '1.0', END)  
      
    # returns to widget currently in focus  
    s = edit.get() 
      
    if (s):  
        idx = '1.0'
        while 1:  
            # searches for desried string from index 1  
            idx = text.search(s, idx, nocase = 1,  
                            stopindex = END) 
              
            if not idx: break
            # last index sum of current index and  
            # length of text  
            lastidx = '% s+% dc' % (idx, len(s)) 
  
            # overwrite 'Found' at idx  
            text.tag_add('found', idx, lastidx)  
            idx = lastidx  
  
        # mark located string as red 
          
        text.tag_config('found', foreground ='red') 
    edit.focus_set() 
  
def findNreplace():  
    # remove tag 'found' from index 1 to END  
    text.tag_remove('found', '1.0', END)  
      
    # returns to widget currently in focus  
    s = edit.get() 
    r = edit2.get() 
      
    if (s and r):  
        idx = '1.0'
        while 1:  
            # searches for desried string from index 1  
            idx = text.search(s, idx, nocase = 1,  
                            stopindex = END) 
            print(idx) 
            if not idx: break
              
            # last index sum of current index and  
            # length of text  
            lastidx = '% s+% dc' % (idx, len(s)) 
  
            text.delete(idx, lastidx) 
            text.insert(idx, r) 
  
            lastidx = '% s+% dc' % (idx, len(r)) 
              
            # overwrite 'Found' at idx  
            text.tag_add('found', idx, lastidx)  
            idx = lastidx  
  
        # mark located string as red 
        text.tag_config('found', foreground ='green', background = 'yellow') 
    edit.focus_set() 
                  
Find.config(command = find) 
replace.config(command = findNreplace) 
  
# mainloop function calls the endless  
# loop of the window, so the window will 
# wait for any user interaction till we 
# close it  
root.mainloop() 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM