Reputation: 1578
I have a problem with the usage of the pyqt5 QTimer class and OSX.
If following simple application gets minimized by clicking on the yellow button on the top left of the window, the application moves as expected to the bottom right of the dock bar and the timer increases every second.
The strange thing is, that after circa 2:30 minutes the timer slows extremly down counting, lets say every 10 seconds. I suspect that this has something to do with a "freeze" or "sleep" mode under OSX?
What I want to have is a reliable timer wich counts every second. Is there a some trick under pyqt that I'm missing?
---- EDIT ----
This also happens if the window looses focus.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
class Main(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.seconds = 0
self.init_ui()
def init_ui(self):
self.timer = QTimer()
self.timer.setInterval(1000)
self.timer.setTimerType(Qt.PreciseTimer)
self.timer.timeout.connect(self.on_timer)
self.timer.start()
@pyqtSlot()
def on_timer(self):
self.seconds += 1
print(time.strftime("%H:%M:%S", time.gmtime(self.seconds)))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
screen = Main()
screen.show()
sys.exit(app.exec_())
Some informations of my system:
Python: 3.4.3
PyQt: 5.4.0
OSX: 10.9.5
uname -a: Darwin mac-pro 13.4.0 Darwin Kernel Version 13.4.0: Wed Mar 18 16:20:14 PDT 2015; root:xnu-2422.115.14~1/RELEASE_X86_64 x86_64
Upvotes: 1
Views: 2054
Reputation: 1578
Additionally to @deets, this would be another possible solution with checking the starttime and using a delta for calculating the offset to that starttime. At least it works for me now:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import os
from datetime import datetime
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QObject, QTimer, QThread, pyqtSlot, pyqtSignal
class Main(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.ellapsed_sec = 0
self.init_ui()
def init_ui(self):
self.timer = QTimer()
self.timer.setInterval(1000)
self.timer.setTimerType(Qt.PreciseTimer)
self.timer.timeout.connect(self.on_timer)
self.timestamp_start = datetime.now()
self.timer.start(1000)
@pyqtSlot()
def on_timer(self):
self.ellapsed_sec += 1
delta = datetime.now() - self.timestamp_start
delta = delta.total_seconds()
if self.ellapsed_sec != delta:
print('Using delta', delta)
self.ellapsed_sec = delta
print(time.strftime("%H:%M:%S", time.gmtime(self.ellapsed_sec)))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
screen = Main()
screen.show()
sys.exit(app.exec_())
Upvotes: 0
Reputation: 6395
This is probably related to a feature of OS X called "AppNap" which will aggressively reduces timer triggering, and syncs them even between apps, to conserve battery life.
You can turn it off via commandline on a per-app-basis using the command
defaults write <domain> NSAppSleepDisabled -bool YES
where <domain>
is your applications bundle-identifier. You can even invoke that within your app via subprocess - that's what I did.
It is not an ideal solution though, consider working around the timer. There might be other ways to solve this depending on your actual use-case.
Upvotes: 1