Как сделать таймер на Python?

Как сделать таймер на Python? При включение таймер просит ввести дату, после чего запускается и ждет пока нужная дата не настанет, а после наступления оповещает пользователя.

Вот пример кода

'''
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
'''
from PyQt5.Qt import *
#from docxtpl import DocxTemplate                   # pip install docxtpl

#from test_ui import Ui_MainWindow
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(320, 240)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setObjectName(u"pushButton")
        self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
        self.tableWidget = QTableWidget(self.centralwidget)
        if (self.tableWidget.columnCount() < 2):
            self.tableWidget.setColumnCount(2)
        __qtablewidgetitem = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
        __qtablewidgetitem1 = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
        if (self.tableWidget.rowCount() < 3):
            self.tableWidget.setRowCount(3)
        __qtablewidgetitem2 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, __qtablewidgetitem2)
        __qtablewidgetitem3 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(1, __qtablewidgetitem3)
        __qtablewidgetitem4 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(2, __qtablewidgetitem4)
        self.tableWidget.setObjectName(u"tableWidget")
        self.tableWidget.horizontalHeader().setDefaultSectionSize(130)
        self.gridLayout.addWidget(self.tableWidget, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 320, 21))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435", None))
        ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0)
        ___qtablewidgetitem.setText(QCoreApplication.translate("MainWindow", u"\u0414\u0430\u0442\u0430", None));
        ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1)
        ___qtablewidgetitem1.setText(QCoreApplication.translate("MainWindow", u"\u041e\u0431\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f, \u0447\u0430\u0441", None));
        ___qtablewidgetitem2 = self.tableWidget.verticalHeaderItem(0)
        ___qtablewidgetitem2.setText(QCoreApplication.translate("MainWindow", u"1", None));
        ___qtablewidgetitem3 = self.tableWidget.verticalHeaderItem(1)
        ___qtablewidgetitem3.setText(QCoreApplication.translate("MainWindow", u"2", None));
        ___qtablewidgetitem4 = self.tableWidget.verticalHeaderItem(2)
        ___qtablewidgetitem4.setText(QCoreApplication.translate("MainWindow", u"3", None));
        

class MainWindow(QMainWindow, Ui_MainWindow):   
    def __init__(self):
        super().__init__()
        
        self.setupUi(self)
        self.pushButton.clicked.connect(self.buttonLoader)
        
        for row in range(self.tableWidget.rowCount()):
            date_from = QDateTimeEdit()
            date_from.setDateTime(
                QDateTime(QDate(2021, 9, 2))
            )
            date_from.dateTimeChanged.connect(
                lambda dateTime, row=row: self.date_changed(dateTime, row))
            self.tableWidget.setCellWidget(row, 0, date_from)

        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, 0)             
        self.tableWidget.setItem(0, 1, item)
        
        for row in range(1, self.tableWidget.rowCount()):    
            dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row, 1, item) 

    def date_changed(self, dateTime, row):
        if row == 0:
            dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row+1, 1, item) 
            return
            
        dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
        dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
        self.tableWidget.setItem(row, 1, item) 
        
        if row != self.tableWidget.rowCount() - 1:
            dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row+1, 1, item)                 
        
    def buttonLoader(self):
        pass
        data_for_word = []
        rows = self.tableWidget.rowCount()
        cols = self.tableWidget.columnCount()
        for row in range(rows):
            dateTime = self.tableWidget.cellWidget(row, 0).\
                       dateTime().toString('dd.MM.yyyy hh:mm')
            item = self.tableWidget.item(row, 1)
            _data = item.data(Qt.DisplayRole)
            data_for_word.append([dateTime, _data])
        
        print(f'\n{data_for_word}\n')
        print(* data_for_word, sep='\n')                      


'''    
        doc = DocxTemplate('test_ui.docx')
        context = {
            'tbl_contents': data_for_word
        }
        doc.render(context)
        doc.save('table.docx')        
'''


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    app.setFont(QFont("Times", 10, QFont.Bold))
    w = MainWindow()
    w.resize(320, 240)
    w.show()
    sys.exit(app.exec_())

Ответы (2 шт):

Автор решения: S. Nick

Класс QTimer предоставляет повторяющиеся и однократные таймеры.

Больше https://doc.qt.io/qt-5/qtimer.html

Заполните колонку Дата и смотрите что происходит.

from PyQt5.Qt import *


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(320, 240)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setObjectName(u"pushButton")
        self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
        self.tableWidget = QTableWidget(self.centralwidget)
        if (self.tableWidget.columnCount() < 2):
            self.tableWidget.setColumnCount(2)
        __qtablewidgetitem = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
        __qtablewidgetitem1 = QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
        if (self.tableWidget.rowCount() < 3):
            self.tableWidget.setRowCount(3)
        __qtablewidgetitem2 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, __qtablewidgetitem2)
        __qtablewidgetitem3 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(1, __qtablewidgetitem3)
        __qtablewidgetitem4 = QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(2, __qtablewidgetitem4)
        self.tableWidget.setObjectName(u"tableWidget")
        self.tableWidget.horizontalHeader().setDefaultSectionSize(130)
        self.gridLayout.addWidget(self.tableWidget, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 320, 21))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435", None))
        ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0)
        ___qtablewidgetitem.setText(QCoreApplication.translate("MainWindow", u"\u0414\u0430\u0442\u0430", None));
        ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1)
        ___qtablewidgetitem1.setText(QCoreApplication.translate("MainWindow", u"\u041e\u0431\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f, \u0447\u0430\u0441", None));
        ___qtablewidgetitem2 = self.tableWidget.verticalHeaderItem(0)
        ___qtablewidgetitem2.setText(QCoreApplication.translate("MainWindow", u"1", None));
        ___qtablewidgetitem3 = self.tableWidget.verticalHeaderItem(1)
        ___qtablewidgetitem3.setText(QCoreApplication.translate("MainWindow", u"2", None));
        ___qtablewidgetitem4 = self.tableWidget.verticalHeaderItem(2)
        ___qtablewidgetitem4.setText(QCoreApplication.translate("MainWindow", u"3", None));
        

class MainWindow(QMainWindow, Ui_MainWindow):   
    def __init__(self):
        super().__init__()
        
        self.setupUi(self)
        self.pushButton.clicked.connect(self.buttonLoader)
        
        for row in range(self.tableWidget.rowCount()):
            date_from = QDateTimeEdit()
            date_from.setDateTime(
                QDateTime(QDate(2021, 9, 4))
            )
            date_from.dateTimeChanged.connect(
                lambda dateTime, row=row: self.date_changed(dateTime, row))
            self.tableWidget.setCellWidget(row, 0, date_from)

        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, 0)             
        self.tableWidget.setItem(0, 1, item)
        
        for row in range(1, self.tableWidget.rowCount()):    
            dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row, 1, item) 

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv            
        self.data_Time = {}                                     # +++
        self.timer = QTimer()                                   # +++
        self.timer.setInterval(1000 * 60)                       # минута
        self.timer.timeout.connect(self.timerUpdate)
        self.timer.start()
        
        QTimer.singleShot(10 , self.x_y)
        
    def x_y(self):                                              # +++
        self.x = self.pos().x() + 330
        self.y = self.pos().y() - 100
        
    def timerUpdate(self):                                      # +++
        current_time = QDateTime.currentDateTime().toString('dd.MM.yyyy hh:mm')
        data_time = self.data_Time.get(current_time)
        if data_time:
            msgBox = QMessageBox(self)
            msgBox.setWindowTitle("ВНИМАНИЕ")
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setText(
                'Пришло время, делайте что-нибудь!<br>'
                f'Дата-время   : {current_time}<br>'
                f'Смотри строку: {data_time[0]}<br>'
                f'Общее время  : {data_time[1]}'
            )
            msgBox.move(self.x, self.y)
            self.y += 150
            msgBox.show()
            
    def updateDict(self):                                      # +++
        self.data_Time = {}
        rows = self.tableWidget.rowCount()
        for row in range(rows):
            dateTime = self.tableWidget.cellWidget(row, 0).\
                       dateTime().toString('dd.MM.yyyy hh:mm')
            item = self.tableWidget.item(row, 1)
            _data = item.data(Qt.DisplayRole)
            self.data_Time[dateTime] = [row, _data]   

# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    def date_changed(self, dateTime, row):
        if row == 0:
            dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row+1, 1, item) 
            
            self.updateDict()                                      # +++
            return
            
        dateTime1 = self.tableWidget.cellWidget(row-1, 0).dateTime()
        dateTime2 = self.tableWidget.cellWidget(row, 0).dateTime()
        item = QTableWidgetItem()
        item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
        self.tableWidget.setItem(row, 1, item) 
        
        if row != self.tableWidget.rowCount() - 1:
            dateTime1 = self.tableWidget.cellWidget(row, 0).dateTime()
            dateTime2 = self.tableWidget.cellWidget(row+1, 0).dateTime()
            item = QTableWidgetItem()
            item.setData(Qt.DisplayRole, dateTime1.secsTo(dateTime2) / 60. / 60.)             
            self.tableWidget.setItem(row+1, 1, item)
            
        self.updateDict()                                           # +++         
        
    def buttonLoader(self):
        data_for_word = []
        rows = self.tableWidget.rowCount()
        cols = self.tableWidget.columnCount()
        for row in range(rows):
            dateTime = self.tableWidget.cellWidget(row, 0).\
                       dateTime().toString('dd.MM.yyyy hh:mm')
            item = self.tableWidget.item(row, 1)
            _data = item.data(Qt.DisplayRole)
            data_for_word.append([dateTime, _data])


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    app.setFont(QFont("Times", 10, QFont.Bold))
    w = MainWindow()
    w.resize(320, 240)
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка
Автор решения: ganz
  1. диалоговое окно на tkinter c вводом даты-времени (точнее с получением значения int так как tkinter не умеет выводить диалог времени) 2*) безконечный цикл с ожиданием *- в сравнении лучше использовать не равенство иначе есть ничтожная доля вероятности пропуска нужного времени (это вызывается загруженостью процессора)
→ Ссылка