Clipboard detector in Python

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite












The following contains my little app that detects changes to the clipboard and displays them in the GUI. I did my best using my limited knowledge of Python, but I have a feeling that I can definitely improve the program. It works, but Python's CPU usage shoots up to 20% whenever I run the program - which is due to my use of multiple threads and infinite loops I'm sure.



#! python3

#GUI
import tkinter
#needed for the clipboard event detection
import time
import threading

#listener class that inherits from Thread
class ClipListener(threading.Thread):
#overriding Thread constructor
def __init__(self, pause = .5):
#from documentation: If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.
super().__init__() #calls Thread class constructor first

#initialize parameters
self.pause = pause
self.stopping = False

#initialize event to communicate with main thread
self.copyevent = threading.Event()

#override run method
def run(self):
last_value = tkinter.Tk().clipboard_get() #initialize last_value as

#continue until self.stopping = true
while not self.stopping:
#grab clip_board value
temp_value = tkinter.Tk().clipboard_get()
#if last value is not equal to the temp_value, then (obviously) a change has occurred
if temp_value != last_value:
#set last value equal to current (temp) value and print
last_value = temp_value
print("set")
#set the event if clipboard has changed
self.copyevent.set()
time.sleep(self.pause) #sleep for indicated amount of time (.5 by default)

#override stop method to work with our paramter 'stopping'
def stop(self):
self.stopping = True

#GUI extends Frame, serving as main container for a root window
class GUI(tkinter.Frame):

#constructor for GUI - intializes with a default height and width if none are given
def __init__(self, master, ht=600, wt=800):

#uses the parent class' constructor
super().__init__(master, height=ht, width=wt)
self.var = tkinter.StringVar()
self.var.set("No copied text")
self.pack_propagate(False) #window will use it's own width and height as parameters instead of child's dimensions
self.pack()
self.label = tkinter.Label(self, textvariable=self.var)
self.label.pack()

#method to update the label
def update_label(self, newText):
self.var.set(newText)
self.label.pack()



def main():
#good practice to have a variable to stop the loop
running = True

#GUI initialized
root = tkinter.Tk()
gui = GUI(root)

#start thread containing Clipboard Listener
listener = ClipListener(.100)
listener.start()


#loop to keep updating the program without blocking the clipboard checks (since mainloop() is blocking)
while running:
#update the gui
root.update();
#wait .1 seconds for event to be set to true
event_set = listener.copyevent.wait(.100)
#if true then update the label and reset event
if event_set:
gui.update_label(root.clipboard_get())
listener.copyevent.clear()


#only run this program if it is being used as the main program file
if __name__ == "__main__":
main()






share|improve this question



























    up vote
    3
    down vote

    favorite












    The following contains my little app that detects changes to the clipboard and displays them in the GUI. I did my best using my limited knowledge of Python, but I have a feeling that I can definitely improve the program. It works, but Python's CPU usage shoots up to 20% whenever I run the program - which is due to my use of multiple threads and infinite loops I'm sure.



    #! python3

    #GUI
    import tkinter
    #needed for the clipboard event detection
    import time
    import threading

    #listener class that inherits from Thread
    class ClipListener(threading.Thread):
    #overriding Thread constructor
    def __init__(self, pause = .5):
    #from documentation: If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.
    super().__init__() #calls Thread class constructor first

    #initialize parameters
    self.pause = pause
    self.stopping = False

    #initialize event to communicate with main thread
    self.copyevent = threading.Event()

    #override run method
    def run(self):
    last_value = tkinter.Tk().clipboard_get() #initialize last_value as

    #continue until self.stopping = true
    while not self.stopping:
    #grab clip_board value
    temp_value = tkinter.Tk().clipboard_get()
    #if last value is not equal to the temp_value, then (obviously) a change has occurred
    if temp_value != last_value:
    #set last value equal to current (temp) value and print
    last_value = temp_value
    print("set")
    #set the event if clipboard has changed
    self.copyevent.set()
    time.sleep(self.pause) #sleep for indicated amount of time (.5 by default)

    #override stop method to work with our paramter 'stopping'
    def stop(self):
    self.stopping = True

    #GUI extends Frame, serving as main container for a root window
    class GUI(tkinter.Frame):

    #constructor for GUI - intializes with a default height and width if none are given
    def __init__(self, master, ht=600, wt=800):

    #uses the parent class' constructor
    super().__init__(master, height=ht, width=wt)
    self.var = tkinter.StringVar()
    self.var.set("No copied text")
    self.pack_propagate(False) #window will use it's own width and height as parameters instead of child's dimensions
    self.pack()
    self.label = tkinter.Label(self, textvariable=self.var)
    self.label.pack()

    #method to update the label
    def update_label(self, newText):
    self.var.set(newText)
    self.label.pack()



    def main():
    #good practice to have a variable to stop the loop
    running = True

    #GUI initialized
    root = tkinter.Tk()
    gui = GUI(root)

    #start thread containing Clipboard Listener
    listener = ClipListener(.100)
    listener.start()


    #loop to keep updating the program without blocking the clipboard checks (since mainloop() is blocking)
    while running:
    #update the gui
    root.update();
    #wait .1 seconds for event to be set to true
    event_set = listener.copyevent.wait(.100)
    #if true then update the label and reset event
    if event_set:
    gui.update_label(root.clipboard_get())
    listener.copyevent.clear()


    #only run this program if it is being used as the main program file
    if __name__ == "__main__":
    main()






    share|improve this question























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      The following contains my little app that detects changes to the clipboard and displays them in the GUI. I did my best using my limited knowledge of Python, but I have a feeling that I can definitely improve the program. It works, but Python's CPU usage shoots up to 20% whenever I run the program - which is due to my use of multiple threads and infinite loops I'm sure.



      #! python3

      #GUI
      import tkinter
      #needed for the clipboard event detection
      import time
      import threading

      #listener class that inherits from Thread
      class ClipListener(threading.Thread):
      #overriding Thread constructor
      def __init__(self, pause = .5):
      #from documentation: If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.
      super().__init__() #calls Thread class constructor first

      #initialize parameters
      self.pause = pause
      self.stopping = False

      #initialize event to communicate with main thread
      self.copyevent = threading.Event()

      #override run method
      def run(self):
      last_value = tkinter.Tk().clipboard_get() #initialize last_value as

      #continue until self.stopping = true
      while not self.stopping:
      #grab clip_board value
      temp_value = tkinter.Tk().clipboard_get()
      #if last value is not equal to the temp_value, then (obviously) a change has occurred
      if temp_value != last_value:
      #set last value equal to current (temp) value and print
      last_value = temp_value
      print("set")
      #set the event if clipboard has changed
      self.copyevent.set()
      time.sleep(self.pause) #sleep for indicated amount of time (.5 by default)

      #override stop method to work with our paramter 'stopping'
      def stop(self):
      self.stopping = True

      #GUI extends Frame, serving as main container for a root window
      class GUI(tkinter.Frame):

      #constructor for GUI - intializes with a default height and width if none are given
      def __init__(self, master, ht=600, wt=800):

      #uses the parent class' constructor
      super().__init__(master, height=ht, width=wt)
      self.var = tkinter.StringVar()
      self.var.set("No copied text")
      self.pack_propagate(False) #window will use it's own width and height as parameters instead of child's dimensions
      self.pack()
      self.label = tkinter.Label(self, textvariable=self.var)
      self.label.pack()

      #method to update the label
      def update_label(self, newText):
      self.var.set(newText)
      self.label.pack()



      def main():
      #good practice to have a variable to stop the loop
      running = True

      #GUI initialized
      root = tkinter.Tk()
      gui = GUI(root)

      #start thread containing Clipboard Listener
      listener = ClipListener(.100)
      listener.start()


      #loop to keep updating the program without blocking the clipboard checks (since mainloop() is blocking)
      while running:
      #update the gui
      root.update();
      #wait .1 seconds for event to be set to true
      event_set = listener.copyevent.wait(.100)
      #if true then update the label and reset event
      if event_set:
      gui.update_label(root.clipboard_get())
      listener.copyevent.clear()


      #only run this program if it is being used as the main program file
      if __name__ == "__main__":
      main()






      share|improve this question













      The following contains my little app that detects changes to the clipboard and displays them in the GUI. I did my best using my limited knowledge of Python, but I have a feeling that I can definitely improve the program. It works, but Python's CPU usage shoots up to 20% whenever I run the program - which is due to my use of multiple threads and infinite loops I'm sure.



      #! python3

      #GUI
      import tkinter
      #needed for the clipboard event detection
      import time
      import threading

      #listener class that inherits from Thread
      class ClipListener(threading.Thread):
      #overriding Thread constructor
      def __init__(self, pause = .5):
      #from documentation: If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.
      super().__init__() #calls Thread class constructor first

      #initialize parameters
      self.pause = pause
      self.stopping = False

      #initialize event to communicate with main thread
      self.copyevent = threading.Event()

      #override run method
      def run(self):
      last_value = tkinter.Tk().clipboard_get() #initialize last_value as

      #continue until self.stopping = true
      while not self.stopping:
      #grab clip_board value
      temp_value = tkinter.Tk().clipboard_get()
      #if last value is not equal to the temp_value, then (obviously) a change has occurred
      if temp_value != last_value:
      #set last value equal to current (temp) value and print
      last_value = temp_value
      print("set")
      #set the event if clipboard has changed
      self.copyevent.set()
      time.sleep(self.pause) #sleep for indicated amount of time (.5 by default)

      #override stop method to work with our paramter 'stopping'
      def stop(self):
      self.stopping = True

      #GUI extends Frame, serving as main container for a root window
      class GUI(tkinter.Frame):

      #constructor for GUI - intializes with a default height and width if none are given
      def __init__(self, master, ht=600, wt=800):

      #uses the parent class' constructor
      super().__init__(master, height=ht, width=wt)
      self.var = tkinter.StringVar()
      self.var.set("No copied text")
      self.pack_propagate(False) #window will use it's own width and height as parameters instead of child's dimensions
      self.pack()
      self.label = tkinter.Label(self, textvariable=self.var)
      self.label.pack()

      #method to update the label
      def update_label(self, newText):
      self.var.set(newText)
      self.label.pack()



      def main():
      #good practice to have a variable to stop the loop
      running = True

      #GUI initialized
      root = tkinter.Tk()
      gui = GUI(root)

      #start thread containing Clipboard Listener
      listener = ClipListener(.100)
      listener.start()


      #loop to keep updating the program without blocking the clipboard checks (since mainloop() is blocking)
      while running:
      #update the gui
      root.update();
      #wait .1 seconds for event to be set to true
      event_set = listener.copyevent.wait(.100)
      #if true then update the label and reset event
      if event_set:
      gui.update_label(root.clipboard_get())
      listener.copyevent.clear()


      #only run this program if it is being used as the main program file
      if __name__ == "__main__":
      main()








      share|improve this question












      share|improve this question




      share|improve this question








      edited Jan 14 at 23:40









      Jamal♦

      30.1k11114225




      30.1k11114225









      asked Jan 8 at 10:59









      avghdev

      283




      283




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          Don't use threads



          You don't need the complexities of threading for this problem. You can use the Tkinter method after to run a function periodically. Threading is necessary if the function you are running takes a long time, but that is not the case here.



          You can use a class, but to keep this answer simple I'll only show the function.



          Also, note that I use an existing window rather than tkinter.Tk() on each call. There's no need to create a new root window every time you do the check.



          def check_clipboard(window):
          temp_value = window.clipboard_get()
          ...


          Next, create a function that calls this function every half second:



          def run_listener(window, interval):
          check_clipboard(window)
          root.after(interval, run_listener, window, interval)


          To start running, simply call run_listener once, and it will continue to run every 500 milliseconds:



          run_listener(root, 500)


          The logic to stop and pause is roughly the same as what you have now. Create a flag, and then check that flag inside of run_check_periodically.



          With this, you can remove the loop from main since tkinter already has an efficient loop:



          def main():
          root = tkinter.Tk()
          gui = GUI(root)

          # start the listener
          listen_to_clipboard(root)

          # start the GUI loop
          root.mainloop()





          share|improve this answer





















          • Thank you so much - I finally got around to implementing these concepts and it reduced my CPU usage by over 65% haha
            – avghdev
            Jan 9 at 19:12










          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184570%2fclipboard-detector-in-python%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          2
          down vote



          accepted










          Don't use threads



          You don't need the complexities of threading for this problem. You can use the Tkinter method after to run a function periodically. Threading is necessary if the function you are running takes a long time, but that is not the case here.



          You can use a class, but to keep this answer simple I'll only show the function.



          Also, note that I use an existing window rather than tkinter.Tk() on each call. There's no need to create a new root window every time you do the check.



          def check_clipboard(window):
          temp_value = window.clipboard_get()
          ...


          Next, create a function that calls this function every half second:



          def run_listener(window, interval):
          check_clipboard(window)
          root.after(interval, run_listener, window, interval)


          To start running, simply call run_listener once, and it will continue to run every 500 milliseconds:



          run_listener(root, 500)


          The logic to stop and pause is roughly the same as what you have now. Create a flag, and then check that flag inside of run_check_periodically.



          With this, you can remove the loop from main since tkinter already has an efficient loop:



          def main():
          root = tkinter.Tk()
          gui = GUI(root)

          # start the listener
          listen_to_clipboard(root)

          # start the GUI loop
          root.mainloop()





          share|improve this answer





















          • Thank you so much - I finally got around to implementing these concepts and it reduced my CPU usage by over 65% haha
            – avghdev
            Jan 9 at 19:12














          up vote
          2
          down vote



          accepted










          Don't use threads



          You don't need the complexities of threading for this problem. You can use the Tkinter method after to run a function periodically. Threading is necessary if the function you are running takes a long time, but that is not the case here.



          You can use a class, but to keep this answer simple I'll only show the function.



          Also, note that I use an existing window rather than tkinter.Tk() on each call. There's no need to create a new root window every time you do the check.



          def check_clipboard(window):
          temp_value = window.clipboard_get()
          ...


          Next, create a function that calls this function every half second:



          def run_listener(window, interval):
          check_clipboard(window)
          root.after(interval, run_listener, window, interval)


          To start running, simply call run_listener once, and it will continue to run every 500 milliseconds:



          run_listener(root, 500)


          The logic to stop and pause is roughly the same as what you have now. Create a flag, and then check that flag inside of run_check_periodically.



          With this, you can remove the loop from main since tkinter already has an efficient loop:



          def main():
          root = tkinter.Tk()
          gui = GUI(root)

          # start the listener
          listen_to_clipboard(root)

          # start the GUI loop
          root.mainloop()





          share|improve this answer





















          • Thank you so much - I finally got around to implementing these concepts and it reduced my CPU usage by over 65% haha
            – avghdev
            Jan 9 at 19:12












          up vote
          2
          down vote



          accepted







          up vote
          2
          down vote



          accepted






          Don't use threads



          You don't need the complexities of threading for this problem. You can use the Tkinter method after to run a function periodically. Threading is necessary if the function you are running takes a long time, but that is not the case here.



          You can use a class, but to keep this answer simple I'll only show the function.



          Also, note that I use an existing window rather than tkinter.Tk() on each call. There's no need to create a new root window every time you do the check.



          def check_clipboard(window):
          temp_value = window.clipboard_get()
          ...


          Next, create a function that calls this function every half second:



          def run_listener(window, interval):
          check_clipboard(window)
          root.after(interval, run_listener, window, interval)


          To start running, simply call run_listener once, and it will continue to run every 500 milliseconds:



          run_listener(root, 500)


          The logic to stop and pause is roughly the same as what you have now. Create a flag, and then check that flag inside of run_check_periodically.



          With this, you can remove the loop from main since tkinter already has an efficient loop:



          def main():
          root = tkinter.Tk()
          gui = GUI(root)

          # start the listener
          listen_to_clipboard(root)

          # start the GUI loop
          root.mainloop()





          share|improve this answer













          Don't use threads



          You don't need the complexities of threading for this problem. You can use the Tkinter method after to run a function periodically. Threading is necessary if the function you are running takes a long time, but that is not the case here.



          You can use a class, but to keep this answer simple I'll only show the function.



          Also, note that I use an existing window rather than tkinter.Tk() on each call. There's no need to create a new root window every time you do the check.



          def check_clipboard(window):
          temp_value = window.clipboard_get()
          ...


          Next, create a function that calls this function every half second:



          def run_listener(window, interval):
          check_clipboard(window)
          root.after(interval, run_listener, window, interval)


          To start running, simply call run_listener once, and it will continue to run every 500 milliseconds:



          run_listener(root, 500)


          The logic to stop and pause is roughly the same as what you have now. Create a flag, and then check that flag inside of run_check_periodically.



          With this, you can remove the loop from main since tkinter already has an efficient loop:



          def main():
          root = tkinter.Tk()
          gui = GUI(root)

          # start the listener
          listen_to_clipboard(root)

          # start the GUI loop
          root.mainloop()






          share|improve this answer













          share|improve this answer



          share|improve this answer











          answered Jan 8 at 13:29









          Bryan Oakley

          1,494712




          1,494712











          • Thank you so much - I finally got around to implementing these concepts and it reduced my CPU usage by over 65% haha
            – avghdev
            Jan 9 at 19:12
















          • Thank you so much - I finally got around to implementing these concepts and it reduced my CPU usage by over 65% haha
            – avghdev
            Jan 9 at 19:12















          Thank you so much - I finally got around to implementing these concepts and it reduced my CPU usage by over 65% haha
          – avghdev
          Jan 9 at 19:12




          Thank you so much - I finally got around to implementing these concepts and it reduced my CPU usage by over 65% haha
          – avghdev
          Jan 9 at 19:12












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184570%2fclipboard-detector-in-python%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Python Lists

          Aion

          JavaScript Array Iteration Methods