I am trying to create a function which accepts a list of items and iterates through them with a specified time interval (using QTimer from the Qt framework), without disrupting the rest of the program flow.
I've managed to get this working with the following code which uses an inner function, but I'm curious if this could be done in a more elegant way, without using the self.index
instance variable. Ideally this counter should be encapsulated within the iterate_with_interval
method, but I couldn't find a way to increment it without using global
.
I suppose this could be done with a dedicated class for this functionality but I'm wondering if it can be done without one.
from PySide6.QtCore import QTimer
from PySide6.QtWidgets import QWidget, QApplication
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.index = 0
self.iterate_with_interval(['a', 'b', 'c', 'd', 'e'], 200)
print('Execution continues')
def iterate_with_interval(self, items, interval):
timer = QTimer()
timer.setInterval(interval)
def iterate(items, timer):
if self.index < len(items):
print(items[self.index])
self.index += 1
else:
timer.stop()
timer.timeout.connect(lambda: iterate(items, timer))
timer.start()
if __name__ == '__main__':
app = QApplication()
window = MainWindow()
window.show()
app.exec()
You will always need an intermediate function that obtains the value of the list, so the most elegant solution is to create a class that handles the logic through an iterator.
from PySide6.QtCore import QTimer, Signal
from PySide6.QtWidgets import QWidget, QApplication
class TimerIterator(QTimer):
value_changed = Signal(object)
def __init__(self, values=None, parent=None):
super().__init__(parent)
self._values = []
self.timeout.connect(self.handle_timeout)
self.values = values or []
@property
def values(self):
return self._values
@values.setter
def values(self, values):
self._values = values
self.setProperty("iterator", iter(self.values))
def handle_timeout(self):
try:
value = next(self.property("iterator"))
except StopIteration:
self.stop()
else:
self.value_changed.emit(value)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.timer_iterator = TimerIterator()
self.timer_iterator.values = ["a", "b", "c", "d", "e"]
self.timer_iterator.setInterval(200)
self.timer_iterator.value_changed.connect(print)
self.timer_iterator.start()
if __name__ == "__main__":
app = QApplication()
window = MainWindow()
window.show()
app.exec()