QTimer в pyqt теряет время? - PullRequest
0 голосов
/ 03 марта 2020

Я сделал небольшое приложение для таймера. Кажется, он работает нормально, но когда я запускаю его в фоновом режиме, таймер (который использует QTimer) не работает правильно. Он теряет время: по прошествии 30 минут иногда таймер отключается только на 10 минут.

При просмотре он не работает медленно. Проблема возникает, когда я переключаю рабочие столы (на моей ма c) (хотя это может быть медленным и в некоторых других случаях). Как я могу предотвратить это?

В частности: в приложении есть TimerPanes. Они должны отсчитывать время от установленного времени (например, 3600 секунд). Когда я запускаю это в фоновом режиме и переключаюсь, например, на просмотр видео, может пройти 10 минут (я проверил по системным часам), но обратный отсчет продолжится только 5 минут.

Вот полный code, класс TimerPane - это класс, в котором используется QTimer. Вы можете запустить его, чтобы увидеть, если это происходит и для вас:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

Base = declarative_base()

class Task(Base):
    __tablename__ = 'task'
    id = Column(Integer, primary_key=True)
    name = Column(String(1000), nullable=False)
    time = Column(Integer, nullable=False, default=0)
    color = Column(String(1000), nullable=False, default=0)

engine = create_engine('sqlite:///tasks.db')
Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)
session = Session()

def Convert(t):
    return "{}:{:0>2d}:{:0>2d}".format(t//3600,(t%3600)//60,t%60)

class MainWindow(QMainWindow):

    def __init__(self, tasks, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setWindowTitle("Timer")

        layout1 = QHBoxLayout()

        layout1.addWidget(Frame(tasks))

        layout1.setContentsMargins(0,0,0,0)
        layout1.setSpacing(0)

        self.widget = QWidget()
        self.widget.setLayout(layout1)

        self.scroll = QScrollArea()
        self.scroll.setWidget(self.widget)
        self.setCentralWidget(self.scroll)
        self.scroll.setWidgetResizable(True)


        self.setMinimumSize(100,200)

class Frame(QWidget):
    def __init__(self, tasks, *args, **kwargs):
        super(Frame, self).__init__(*args, **kwargs)
        self.vbox = QVBoxLayout()

        self.create = QPushButton("Create new task")
        self.vbox.addWidget(self.create)
        self.create.clicked.connect(self.showDialog)


        self.setLayout(self.vbox)

        for task in tasks:
            self.vbox.addWidget(TimerPane(task))


    def showDialog(self):
        t=InputDialog()
        if t.exec()==1:
            name, time, color = t.getInputs()
            obj = Task()
            obj.name = name
            obj.time = time
            obj.color= color
            session.add(obj)
            session.commit()
            self.vbox.addWidget(TimerPane(obj))

class TimerPane(QWidget):
    def __init__(self, obj=None, *args, **kwargs):
        super(TimerPane, self).__init__(*args, **kwargs)

        self.setAutoFillBackground(True)
        self.layout=QVBoxLayout()

        BFont=QFont()
        BFont.setBold(True)

        IFont=QFont()
        IFont.setItalic(True)

        self.namelabel=QLabel()
        self.namelabel.setFont(BFont)
        self.layout.addWidget(self.namelabel)

        self.timelabel=QLabel()
        self.timelabel.setFont(IFont)
        self.layout.addWidget(self.timelabel)

        self.timeleftlabel=QLabel()
        self.layout.addWidget(self.timeleftlabel)

        self.setLayout(self.layout)

        self.timeleft=0
        self.time=0
        self.name=''

        if obj:
            self.obj=obj
            self.load()

        self.active=False

        self.deleteButton = QPushButton("Delete")
        self.deleteButton.setSizePolicy(QSizePolicy.Fixed,
            QSizePolicy.Fixed)
        self.layout.addWidget(self.deleteButton)
        self.deleteButton.clicked.connect(self.delete_widget)

    def mousePressEvent(self, event):
        if self.active:
            self.timer_stop()
        else:
            self.timer_start()

    def timer_timeout(self):
        self.timeleft -= 1

        if self.timeleft == 0:
            self.timer_stop()
            self.timeleft = self.obj.time

        self.update_gui()

    def timer_start(self):
        self.my_qtimer = QTimer(self)
        self.my_qtimer.timeout.connect(self.timer_timeout)
        self.my_qtimer.start(1000)
        self.active=True

        self.update_gui()

    def timer_stop(self):
        self.my_qtimer.stop()
        self.active=False

    def update_gui(self,*args):
        self.timeleftlabel.setText(Convert(self.timeleft))

    def load(self):
        p = self.palette()
        p.setColor(self.backgroundRole(), QColor(self.obj.color))
        self.setPalette(p)
        self.name=self.obj.name
        self.time=self.obj.time
        self.timeleft=self.obj.time
        try:
            self.namelabel.setText(self.name)
            self.timelabel.setText(Convert(self.time))
            self.timeleftlabel.setText(Convert(self.timeleft))
            self.active=False
        except:
            print("Error, invalid values, delting object")
            self.delete_widget()

    def delete_widget(self):
        session.delete(self.obj)
        session.commit()
        self.deleteLater()

class InputDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.name = QLineEdit(self)
        self.time = QLineEdit(self)
        self.color= QColor(0, 0, 0).name()


        layout = QFormLayout(self)
        layout.addRow("Name", self.name)
        layout.addRow("Time", self.time)

        self.btn = QPushButton('Color', self)
        layout.addWidget(self.btn)
        self.btn.clicked.connect(self.showColor)

        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self);
        layout.addWidget(buttonBox)

        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)

    def showColor(self):

        col = QColorDialog.getColor()

        if col.isValid():
            self.color=col.name()

    def getInputs(self):
        return (self.name.text(), self.time.text(), self.color)


if __name__ == '__main__':
    app = QApplication([])
    app.setApplicationName("Timer")

    existing_tasks = session.query(Task).all()
    window=MainWindow(existing_tasks)

    window.show()

    app.exec_()

...