Tkinter text widget - check if the text is edited

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • nihilium
    New Member
    • Mar 2008
    • 16

    Tkinter text widget - check if the text is edited

    Using Tkinter in Python 2.7.

    What I need is to be able to check regularly if the text in the widget has been changed. Ideally, I would have been able to call a function each time a change to the text was made or the widget was used, but this seems impossible.

    More specifically, I want to be able to have a label change between "original", "altered", "empty" and "new". Where e.g. "original" refers to a text that was fetched from the Internet, "altered" refers to an "original" that has been edited, and "new" is activated if text is typed in manually after the widget has been "empty".

    Creating a new thread manually to do the comparisons has crossed my mind, but I am not very familiar with threading and was hoping that there was a more elegant way to accomplish this.
  • bvdet
    Recognized Expert Specialist
    • Oct 2006
    • 2851

    #2
    Off the top of my head - Bind the widget to a 'KeyRelease' event which would set a flag that the user modified the text in some way. Also, you could save the original text as an attribute and compare the widget text at selected intervals in a callback using method after().

    Comment

    • dwblas
      Recognized Expert Contributor
      • May 2008
      • 626

      #3
      You did not say which widget you are using, but for an Entry widget, or any widget with a StringVar, you can set the trace option.
      Code:
      import Tkinter
      
      def text_changed(*args):
          print tk_name.get()
      
      top = Tkinter.Tk()
      
      frame_1 = Tkinter.Frame( top )
      frame_1.grid(row=0, column=0)
      
      Tkinter.Label(frame_1, text = "Test Data" ).grid(row=0, column=1)
      
      tk_name=Tkinter.StringVar()
      tk_name.set("abcdef")
      tk_name.trace("w", text_changed)
      
      entry_1 = Tkinter.Entry(frame_1, textvariable=tk_name)
      entry_1.grid(row=1, column=1, sticky="W")
      
      top.mainloop()

      Comment

      • bvdet
        Recognized Expert Specialist
        • Oct 2006
        • 2851

        #4
        Cool. I didn't know about the trace method. :)

        Comment

        • nihilium
          New Member
          • Mar 2008
          • 16

          #5
          Per the title, I am using the Text widget (the text will normally contain several lines). The Text widget does not appear to have a 'textvariable' option.

          Going to try out bvdet's suggestions now.

          Comment

          • dwblas
            Recognized Expert Contributor
            • May 2008
            • 626

            #6
            effbot has an example
            Code:
            import md5
                def getsignature(contents):
                    return md5.md5(contents).digest()
            
                text.insert(END, contents) # original contents
                signature = getsignature(contents)
            
                ...
            
                contents = text.get(1.0, END)
                if signature != getsignature(contents):
                    print "contents have changed!"
            Text widgets can also be bound to "<<Modified >>". I only have one test program so obviously have not done much with this binding, and there is likely a cleaner way to do this, but you can probably find more what you want with a Google for "<<Modified >>".
            Code:
            from Tkinter import *
            
            class TextModified():
                def __init__(self):
            
                    root = Tk()
                    self.txt = Text(master=root)
                    self.txt.pack()
                    self.txt.focus_set()
                    self.txt.bind('<<Modified>>', self.changed)
                    root.mainloop()
            
                def changed(self, value=None):
                    flag = self.txt.edit_modified()
                    print flag
                    if flag:     # prevent from getting called twice
                        print "changed called"
                    ## reset so this will be called on the next change
                    self.txt.edit_modified(False)
            
            TM=TextModified()

            Comment

            • nihilium
              New Member
              • Mar 2008
              • 16

              #7
              By the gods, I have been reading the articles on effbot since I started creating my program, but my CTRL+F-ing did not discover that bit about md5.

              I wanted to report back that bvdet's suggestion, something a la

              Code:
              text = Text(root)
              text.grid()
              text.bind('<Key>', compare)
              
              def compare(args*):
                     # check the text
              seems to do the trick, apart from the fact that the text that 'compare' will get its hands on is the text prior to the key being pressed (apparently).

              Should be a simple workaround for that, though md5/modified will perhaps spare me that work.

              Comment

              • dwblas
                Recognized Expert Contributor
                • May 2008
                • 626

                #8
                As bvdet suggested, use KeyRelease
                Code:
                from Tkinter import *
                
                def compare(*args):
                    # check the text
                    print "compare", text.get(1.0, END),
                
                root = Tk()
                text = Text(root)
                text.grid()
                text.bind('<KeyRelease>', compare)
                text.focus_set()
                
                root.mainloop()

                Comment

                • nihilium
                  New Member
                  • Mar 2008
                  • 16

                  #9
                  Right, that works. :-D

                  It wouldn't "support" copy and paste through right click, but I am not sure if I am going to implement that anyway (and I guess <<modified>> would support it).

                  So I'll consider the case solved for the time being. Thanks for the input.

                  Comment

                  Working...