QTimer случайно останавливается до установленного времени?

Объект QTimer останавливается случайным образом ближе к концу, он не останавливается в одной и той же точке сразу, я не понимаю, почему, поскольку он останавливает как пользовательский виджет, так и саму переменную, поэтому виджет не может его отображать.

import sys
from PySide2.QtWidgets import QWidget, QSlider, QLabel, QProgressBar, QPushButton, QHBoxLayout, QVBoxLayout, QApplication
from PySide2.QtCore import QTimer,Qt
from PySide2extn.RoundProgressBar import roundProgressBar

class Timer(QWidget):
    def __init__(self):
        super().__init__()

        # Create a slider to set the timer duration
        self.slider = QSlider()
        self.slider.setOrientation(Qt.Horizontal) # vertical slider
        self.slider.setRange(1, 60)  # timer duration range: 1-60 seconds
        self.slider.setValue(10)  # default timer duration: 10 seconds
        self.slider.valueChanged.connect(self.update_label)
        self.time=0

        # Create a label to display the current timer duration
        self.label = QLabel(f'Timer duration: {self.slider.value()} seconds')

        # Create a progress bar to show the timer progress
        self.progress = roundProgressBar()
        self.progress.rpb_setRange(0, self.slider.value() * 1000)
        self.progress.rpb_setValue(0)

        # Create start, stop, and reset buttons
        self.start_button = QPushButton('Start')
        self.stop_button = QPushButton('Stop')
        self.reset_button = QPushButton('Reset')
        self.start_button.clicked.connect(self.start_timer)
        self.stop_button.clicked.connect(self.stop_timer)
        self.reset_button.clicked.connect(self.reset_timer)
        self.stop_button.setEnabled(False)
        self.reset_button.setEnabled(False)

        # Create a layout for the buttons
        button_layout = QHBoxLayout()
        button_layout.addWidget(self.start_button)
        button_layout.addWidget(self.stop_button)
        button_layout.addWidget(self.reset_button)

        # Create a layout and add the slider, label, progress bar, and buttons
        layout = QVBoxLayout()
        layout.addWidget(self.slider)
        layout.addWidget(self.label)
        layout.addWidget(self.progress)
        layout.addLayout(button_layout)
        self.setLayout(layout)

        # Create a timer and set the timeout signal
        self.timer = QTimer()
        self.timer.timeout.connect(self.timeout)
        self.progress_timer = QTimer()
        self.progress_timer.timeout.connect(self.update_progress)

    def update_label(self):
        self.label.setText(f'Timer duration: {self.slider.value()} seconds')
        self.progress.rpb_setRange(0, self.slider.value() * 1000)

    def update_progress(self):
        self.time+=100
        print(self.time)
        self.progress.rpb_setValue(self.time)

    def start_timer(self):
        # Set the timer duration in seconds
        duration = self.slider.value()
        # Start the timer and progress timer
        self.timer.start(duration * 1000)  # milliseconds
        self.progress_timer.start(100)  # 100ms interval
        # Disable the start button, enable the stop and reset buttons
        self.start_button.setEnabled(False)
        self.stop_button.setEnabled(True)
        self.reset_button.setEnabled(True)
        self.slider.setEnabled(False)

    def stop_timer(self):
        # Stop the timer and progress timer
        self.timer.stop()
        self.progress_timer.stop()
        # Disable the stop button, enable the start button
        self.stop_button.setEnabled(False)
        self.start_button.setEnabled(True)
        self.slider.setEnabled(True)

    def reset_timer(self):
        # Stop the timer and progress timer
        self.time=0
        self.timer.stop()
        self.progress_timer.stop()
        # Reset the progress bar to 0, enable the start button, disable the stop and reset buttons
        self.progress.rpb_setValue(0)
        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        self.reset_button.setEnabled(False)

    def timeout(self):
         # Stop the timer and progress timer
        self.timer.stop()
        self.progress_timer.stop()
        # Disable the stop button, enable the start button and reset button
        self.stop_button.setEnabled(False)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    timer = Timer()
    timer.show()
    sys.exit(app.exec_())

Спасибо за любую помощь.

НЕ СМЕШИВАЙТЕ PYSIDE2 И PYQT5. Обратитесь к первому комментарию к вопросу о том, почему.

Прежде всего, вы либо используете PyQt, либо PySide, но НИКОГДА не смешиваете их. Также нет PySide3; и если вы имели в виду PySide6, даже игнорируя вышесказанное (а вы не можете), они, конечно, не «идентичны»: PyQt5 для Qt5 и PySide6 для Qt6, и эти версии Qt нельзя использовать одновременно, поскольку они это разные основные версии.

musicamante 15.04.2023 02:34

Извините, я имел в виду PySide2, я пытался использовать все PySide2 и все PyQT5, поэтому вообще не смешивал их, и время все равно останавливалось случайным образом, когда я устанавливаю его на 10 секунд, оно останавливается на 8,9 или 8,7 или 9. и это то же самое для любого Другое время.

john truman 15.04.2023 14:08
Согласно документации точность таймеров зависит от ОС и железа. По умолчанию время таймера равно CoarseTimer, что позволяет поддерживать точность только в 5%. Документы предполагают, что PreciseTimer может быть лучшим вариантом. Однако, если вы используете случайное сочетание несовместимых библиотек и сторонних расширений, ничто не может быть гарантировано.
ekhumoro 15.04.2023 15:28

PS: если вы хотите должным образом проверить точность таймеров на вашей ОС/оборудовании, удалите все виджеты из своего примера и используйте только одну библиотеку. Для этого потребуется всего около десяти строк кода. Попробуйте все типы таймеров. Если вы все еще можете воспроизвести проблему, опубликуйте исправленный тестовый пример и предоставьте подробную информацию об ОС, оборудовании и точных версиях Qt5 и/или Qt6.

ekhumoro 15.04.2023 15:35

@johntruman Тогда, для дальнейшего использования, пожалуйста, будьте более осторожны как с терминологией, так и с кодом. Даже если вы частично исправили свой вопрос, его код все равно недействителен (поскольку он смешивает PyQt и PySide), и это затрудняет понимание, вызвана ли проблема этим или нет: кто читает ваш вопрос, не знает вас, для чего они знают, что проблема могла быть вызвана этим, или они могли предположить, что совместное использование этих привязок уместно; помните, вопросы (и ответы на них) предназначены не только для тех, кто их задает.

musicamante 20.04.2023 07:27

Изменен исходный вопрос, чтобы не вызывать путаницы у тех, кто читает позже, я специально упомянул, что не смешиваю библиотеки и удаляю любые упоминания о PyQT5, поскольку у меня есть код PySide2.

john truman 22.04.2023 14:04
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

То, как вы держите время, не точно. Вы можете продемонстрировать это, внеся следующие изменения:

    def update_progress(self):
        self.time += 100
        elapsed_time = self.timer.interval() - self.timer.remainingTime()
        print(self.time, elapsed_time)
        self.progress.setValue(elapsed_time)

В выводе на печать вы можете видеть, что self.time и elapsed_time не синхронизированы. self.time отстает, и создается впечатление, что таймер останавливается преждевременно, хотя на самом деле он истекает. Использование elapsed_time в качестве значения для установки индикатора выполнения даст точный ход таймера. Однако он все равно не достигнет 100%, потому что момент истечения времени таймера попадет между обновлениями. Если вы уменьшите интервал обновления, вы приблизитесь к 100%.

Это отлично работает, за исключением того, что не позволяет мне останавливать таймер и возобновлять его работу, он перезапускает таймер каждую звезду. Чтобы решить эту проблему, я добавил переменную, которая содержит прошедшее время, когда пользователь останавливает нажатие, при запуске прошедшее время вычитается из общей продолжительности, затем я добавляю эту переменную к переменной прошедшего времени в update_progress(), но это должно быть отличается от переменной той, которая вычисляет текущее прошедшее время.

john truman 15.04.2023 21:53

Вы также можете создать подкласс QTimer, чтобы приостановить и возобновить его работу. Как здесь: stackoverflow.com/a/35794807/6439229

mahkitah 15.04.2023 22:12

Другие вопросы по теме