Clipboard detector in Python

Clash 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()
python performance python-3.x tkinter
add a comment |Â
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()
python performance python-3.x tkinter
add a comment |Â
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()
python performance python-3.x tkinter
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()
python performance python-3.x tkinter
edited Jan 14 at 23:40
Jamalâ¦
30.1k11114225
30.1k11114225
asked Jan 8 at 10:59
avghdev
283
283
add a comment |Â
add a comment |Â
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()
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
add a comment |Â
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()
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
add a comment |Â
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()
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
add a comment |Â
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()
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()
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
add a comment |Â
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
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password