Last active
March 1, 2023 15:52
-
-
Save niccokunzmann/8673951 to your computer and use it in GitHub Desktop.
You can use while and for loops without blocking the GUI. This is currently for Tkinter and PyQT. To install guiLoop copy the guiLoop.py file into the directory of your script.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## MIT License | |
## | |
## Copyright 2014 Nicco Kunzmann | |
## | |
## Permission is hereby granted, free of charge, to any person obtaining a copy of this | |
## software and associated documentation files (the "Software"), to deal in the Software | |
## without restriction, including without limitation the rights to use, copy, modify, merge, | |
## publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | |
## to whom the Software is furnished to do so, subject to the following conditions: | |
## | |
## The above copyright notice and this permission notice shall be included in all copies | |
## or substantial portions of the Software. | |
## | |
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
## INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
## PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | |
## FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
## OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
## DEALINGS IN THE SOFTWARE. | |
""" | |
This script uses a while loop that lets an LED blink while the GUI is still responsive. | |
Running this script outputs | |
LED on shiny! | |
LED off shiny! | |
LED on shiny! | |
LED off shiny! | |
LED on shiny! | |
LED off shiny! | |
while the GUI is responsive. | |
This was created because of an stackoverflow question: | |
http://stackoverflow.com/questions/21411748/python-how-do-i-continuously-repeat-a-sequence-without-a-while-loop-and-still | |
examples: | |
http://stackoverflow.com/questions/21440731/tkinter-getting-key-pressed-event-from-a-function | |
https://gist.github.com/niccokunzmann/8673951#file-example-py | |
https://gist.github.com/niccokunzmann/8673951#file-start_and_stop-py | |
""" | |
try: from Tkinter import * | |
except ImportError: from tkinter import * | |
from guiLoop import guiLoop # https://gist.github.com/niccokunzmann/8673951 | |
@guiLoop | |
def led_blink(argument): | |
while 1: | |
print("LED on " + argument) | |
yield 0.5 # time to wait | |
print("LED off " + argument) | |
yield 0.5 | |
t = Tk() | |
# run led_blink in this GUI | |
led_blink(t, 'shiny!') | |
### you can run several loops at once: | |
##led_blink(t, 'red') | |
##led_blink(t, 'blue') | |
##led_blink(t, 'green') | |
# add a responsive button | |
def button_pressed(): | |
print('button pressed') | |
Button(t, command = button_pressed, text = 'press me').pack() | |
# start the GUI loop | |
t.mainloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## MIT License | |
## | |
## Copyright 2014 Nicco Kunzmann | |
## | |
## Permission is hereby granted, free of charge, to any person obtaining a copy of this | |
## software and associated documentation files (the "Software"), to deal in the Software | |
## without restriction, including without limitation the rights to use, copy, modify, merge, | |
## publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | |
## to whom the Software is furnished to do so, subject to the following conditions: | |
## | |
## The above copyright notice and this permission notice shall be included in all copies | |
## or substantial portions of the Software. | |
## | |
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
## INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
## PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | |
## FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
## OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
## DEALINGS IN THE SOFTWARE. | |
""" | |
This shows how to use guiLoop as an method of a gui element object | |
This script uses a while loop that lets an LED blink while the GUI is still responsive. | |
""" | |
try: from Tkinter import * | |
except ImportError: from tkinter import * | |
from guiLoop import guiLoop # https://gist.github.com/niccokunzmann/8673951 | |
class MyWindow(Tk): | |
def __init__(self): | |
Tk.__init__(self) | |
self.led_blink('blue') | |
@guiLoop | |
def led_blink(self, argument): | |
while 1: | |
print("LED on " + argument) | |
yield 0.5 # time to wait | |
print("LED off " + argument) | |
yield 0.5 | |
t = MyWindow() | |
t.mainloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## MIT License | |
## | |
## Copyright 2014 Nicco Kunzmann | |
## | |
## Permission is hereby granted, free of charge, to any person obtaining a copy of this | |
## software and associated documentation files (the "Software"), to deal in the Software | |
## without restriction, including without limitation the rights to use, copy, modify, merge, | |
## publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | |
## to whom the Software is furnished to do so, subject to the following conditions: | |
## | |
## The above copyright notice and this permission notice shall be included in all copies | |
## or substantial portions of the Software. | |
## | |
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
## INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
## PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | |
## FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
## OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
## DEALINGS IN THE SOFTWARE. | |
""" | |
This script uses a while loop that lets an LED blink while the GUI is still responsive. | |
Running this script outputs | |
LED on shiny! | |
LED off shiny! | |
LED on shiny! | |
LED off shiny! | |
LED on shiny! | |
LED off shiny! | |
while the GUI is responsive. | |
This was created because of an stackoverflow question: | |
http://stackoverflow.com/questions/23057031/how-to-quit-the-program-in-while-loop-using-push-button-in-pyqt/23057966#23057966 | |
""" | |
from PyQt4 import QtGui | |
import sys | |
from guiLoop import guiLoop # https://gist.github.com/niccokunzmann/8673951 | |
@guiLoop | |
def led_blink(argument): | |
while 1: | |
print("LED on " + argument) | |
yield 0.5 # time to wait | |
print("LED off " + argument) | |
yield 0.5 | |
app = QtGui.QApplication(sys.argv) | |
w = QtGui.QWidget() | |
w.resize(250, 150) | |
w.move(300, 300) | |
w.setWindowTitle('Simple') | |
w.show() | |
led_blink(w, 'shiny!') | |
sys.exit(app.exec_()) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## MIT License | |
## | |
## Copyright 2014 Nicco Kunzmann | |
## | |
## Permission is hereby granted, free of charge, to any person obtaining a copy of this | |
## software and associated documentation files (the "Software"), to deal in the Software | |
## without restriction, including without limitation the rights to use, copy, modify, merge, | |
## publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | |
## to whom the Software is furnished to do so, subject to the following conditions: | |
## | |
## The above copyright notice and this permission notice shall be included in all copies | |
## or substantial portions of the Software. | |
## | |
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
## INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
## PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | |
## FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
## OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
## DEALINGS IN THE SOFTWARE. | |
""" | |
guiLoop lets you use while and for loops with GUIs. | |
Usually using loops in GUIs makes them block. | |
This module uses the yield statement in loops to let the GUI update while the loop is still running. | |
See the example.py or start_and_stop.py for examples. | |
The code is available here: https://gist.github.com/niccokunzmann/8673951#file-guiloop-py | |
Currently only tkinter is supported but with a little help this can be adapted to other GUI frameworks, too. | |
Change the function _start_in_gui for different GUI frameworks. | |
If you use this code for an other GUI than tkinter send me your code or | |
leave a comment so that some day this can become a module on pypi.python.org | |
useful for others, too. | |
This was created because of an stackoverflow question: | |
http://stackoverflow.com/questions/21411748/python-how-do-i-continuously-repeat-a-sequence-without-a-while-loop-and-still | |
""" | |
def use_tkinter_after(gui_element, wait_time, call_this): | |
# the following line needs replacement depending on the GUI | |
# it calls 'call_this' after a period of time 'wait_time' in ms | |
# for Tkinter | |
gui_element.after(wait_time, call_this) | |
def use_PyQT4_QTimer(gui_element, wait_time, call_this): | |
from PyQt4.QtCore import QTimer | |
QTimer.singleShot(wait_time, call_this) | |
def use_any_timer(gui_element, wait_time, call_this): | |
if hasattr(gui_element, 'after'): | |
use_tkinter_after(gui_element, wait_time, call_this) | |
elif hasattr(gui_element, 'pyqtConfigure'): | |
use_PyQT4_QTimer(gui_element, wait_time, call_this) | |
else: | |
raise TypeError("Can not automatically detect which GUI this is.") | |
def _loop_in_the_gui(gui_element, generator, _start_in_gui): | |
try: | |
# generator yields the time to wait | |
wait_time = next(generator) | |
except StopIteration: | |
pass | |
else: | |
if wait_time is None: | |
# yield | |
wait_time = 0 | |
else: | |
# yield seconds | |
wait_time = int(wait_time * 1000) # Tkinter works with milli seconds | |
call_this_again = lambda: _loop_in_the_gui(gui_element, generator, | |
_start_in_gui) | |
_start_in_gui(gui_element, wait_time, call_this_again) | |
class guiLoop(object): | |
def __init__(self, function, start_in_gui = use_any_timer): | |
"""make a function to a guiLoop function | |
The resulting function needs a gui element as first argument.""" | |
self.function = function | |
self.__doc__ = function.__doc__ | |
self.__name__ = function.__name__ | |
self.start_in_gui = start_in_gui | |
def __call__(self, gui_element, *args, **kw): | |
generator = self.function(*args, **kw) | |
_loop_in_the_gui(gui_element, generator, self.start_in_gui) | |
return generator | |
def __get__(self, gui_element, cls): | |
if gui_element is None: | |
return self | |
return lambda *args, **kw: self(gui_element, gui_element, *args, **kw) | |
def tkLoop(function): | |
"""a guiLoop for tkinter""" | |
return guiLoop(function, use_tkinter_after) | |
def qt4Loop(function): | |
"""a guiLoop for PyQT4""" | |
return guiLoop(function, use_PyQT4_QTimer) | |
class StopLoopException(Exception): | |
"""This is raised if the loop shall stop""" | |
pass | |
def stopLoop(generator): | |
"""stop the loop | |
Generator is the return value of guiLoop.""" | |
try: generator.throw(StopLoopException()) | |
except StopLoopException: pass | |
__all__ = ['guiLoop', 'stopLoop', 'StopLoopException', 'tkLoop', 'qt4Loop'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## MIT License | |
## | |
## Copyright 2014 Nicco Kunzmann | |
## | |
## Permission is hereby granted, free of charge, to any person obtaining a copy of this | |
## software and associated documentation files (the "Software"), to deal in the Software | |
## without restriction, including without limitation the rights to use, copy, modify, merge, | |
## publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | |
## to whom the Software is furnished to do so, subject to the following conditions: | |
## | |
## The above copyright notice and this permission notice shall be included in all copies | |
## or substantial portions of the Software. | |
## | |
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
## INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
## PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | |
## FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
## OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
## DEALINGS IN THE SOFTWARE. | |
""" | |
This script uses a while loop that lets an LED blink while the GUI is still responsive. | |
It shows how started loops can be interrupted. | |
Example 1 throws an error in the loop and makes it terminate immediately. | |
Example 2 uses a shared variable to exit the loop when the LED is turned off again. | |
This was created because of an stackoverflow question: | |
http://stackoverflow.com/questions/21411748/python-how-do-i-continuously-repeat-a-sequence-without-a-while-loop-and-still | |
""" | |
try: from Tkinter import * | |
except ImportError: from tkinter import * | |
from guiLoop import guiLoop, stopLoop # https://gist.github.com/niccokunzmann/8673951 | |
@guiLoop | |
def led_blink(state): | |
while state != ["stop"]: | |
print("LED on") | |
yield 0.5 # time to wait | |
print("LED off") | |
yield 0.5 | |
t = Tk() | |
def button_pressed1(): | |
"stop the function throwing an error in yield" | |
generator = led_blink(b1, []) | |
def turn_off(): | |
stopLoop(generator) | |
b1["command"] = button_pressed1 | |
b1["command"] = turn_off | |
# this button stops at any yield | |
b1 = Button(t, command = button_pressed1, text = 'press me (1)') | |
b1.pack() | |
def button_pressed2(): | |
"stop the function using a shared variable" | |
state = [] | |
generator = led_blink(b2, state) | |
def turn_off(): | |
state.append("stop") | |
b2["command"] = button_pressed2 | |
b2["command"] = turn_off | |
# this button stops when the loop is done | |
b2 = Button(t, command = button_pressed2, text = 'press me (2)') | |
b2.pack() | |
t.mainloop() |
@AISWARYA2019 you can download it and copy it next to the file you import it from. If you download the ZIP file, the example files should work because the guiLoop is next to them in the same directory.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to install guiLoop ?