본문 바로가기
PyQt5_

Timers

by 자동매매 2023. 3. 13.

31. Timers

In applications you often want to perform some tasks regularly or even just at some point in the future. In PyQt6 this is accomplished by using timers. The QTimer class gives you access to two different types of timer — recurring or interval timers, and single shot or one off timers. Both can be hooked up to functions and methods in your application to cause them to execute whenever you need. In this chapter we’ll look at these two types of timer and demonstrate how you can use them to automate your apps.

Interval timers

Using the QTimer class you can create interval timers for any duration in msecs. On each specified duration, the timer will time out. To trigger something to happen each time this occurs, you connect the timer’s timeout signal to whatever you want to do — just like you would with any other signal.

In the example below we setup up a timer, running every 100 msecs , which rotates a dial.

Listing 232. further/timers_1.py

import sys

from PyQt6.QtCore import QTimer

from PyQt6.QtWidgets import QApplication, QDial, QMainWindow

class MainWindow (QMainWindow):

def __init__ (self):

super().__init__()

self.dial = QDial()

self.dial.setRange( 0 , 100 )

self.dial.setValue( 0 )

self.timer = QTimer()

self.timer.setInterval( 10 )

self.timer.timeout.connect(self.update_dial)

self.timer.start()

self.setCentralWidget(self.dial)

def update_dial (self):

value = self.dial.value()

value += 1 # increment

if value > 100 :

value = 0

self.dial.setValue(value)

app = QApplication(sys.argv)

w = MainWindow()

w.show()

app. exec ()

This is just a simple example — you can do anything you want in the connected methods. However, the standard event loop rules apply and triggered tasks should return quickly to avoid blocking the GUI. If you need to perform regular long-running tasks, you can use the timer to trigger a separate thread or process.

ë

You must keep a reference to the created timer object, for the

duration that the timer is running. If you don’t then the timer

object will be deleted and the timer will stop — without

warning. If you create a timer and it doesn’t seem to be working,

check you’ve kept a reference to the object.

If the accuracy of the timer is important, you can adjust this by passing a Qt.QTimerType value to timer.setTimerType.

Listing 233. further/timers_1b.py

self.timer.setTimerType(Qt.TimerType.PreciseTimer)

The available options are shown below. Don’t make your timers more accurate than they need to be. You may block important UI updates.

Timer type Value Description

Qt.TimerType.PreciseTimer 0 Precise timers try to keep

millisecond accuracy

Qt.TimerType.CoarseTimer 1 Coarse timers try to keep

accuracy within 5% of the

desired interval

Qt.TimerType.VeryCoarseTimer 2 Very coarse timers only keep

full second accuracy

Note that even the most precise timer only tries to keep millisecond accuracy. Anything in the GUI thread risks being blocked by UI updates and your own Python code. If accuracy is that important, then put the work in another thread or process you control completely.

Single shot timers

If you want to trigger something, but only have it occur once, you can use a single

shot timer. These are constructed using static methods on the QTimer object. The simplest form just accepts a time in msecs and whatever callable you want to trigger when the timer fires — for example, the method you want to run.

In the following example we use a single shot timer to uncheck a toggleable push button after its pushed down.

Listing 234. further/timers_2.py

import sys

from PyQt6.QtCore import QTimer

from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton

class MainWindow (QMainWindow):

def __init__ (self):

super().__init__()

self.button = QPushButton("Press me!")

self.button.setCheckable(True)

self.button.setStyleSheet(

# Make the check state red so easier to see.

"QPushButton:checked { background-color: red; }"

)

self.button.toggled.connect(self.button_checked)

self.setCentralWidget(self.button)

def button_checked (self):

print ("Button checked")

QTimer.singleShot( 1000 , self.uncheck_button) ①

def uncheck_button (self):

print ("Button unchecked")

self.button.setChecked(False)

app = QApplication(sys.argv)

w = MainWindow()

w.show()

app. exec ()

①The uncheck_button method will be called after 1000 msecs.

If you run this example and press the button you’ll see it become checked and turn red — using custom styles. Then after a second the button will revert to its

unchecked state.

To achieve this we’ve chained together two custom methods using a single shot timer. First we connect the toggled signal from the button to a method button_checked. This fires off the single shot timer. When this timer times out, it calls uncheck_button which actually unchecks the button. This allows us to postpone the unchecking of the button by a configurable amount.

Unlike interval timers, you don’t need to keep a reference to the created timer — the QTimer.singleShot() method doesn’t return one.

Postponing-via the event queue

You can use zero-timed single shot timers to postpone operations via the event queue. When the timer is triggered the timer event goes to the back of the event queue (as it is a new event) and will only get processed once all existing events have been processed.

Remember that signals (and events) are only processed once you return control from Python to the event loop. If you trigger a series of signals in a method, and want to do something after they’ve occurred, you can’t do it directly in the same method. The code there will be executed before the signals take effect.

def my_method (self):

self.some_signal.emit()

self.some_other_signal.emit()

do_something_here() ①

①This function will be executed before the two signals take effect.

By using a single shot timer you can push the subsequent operation to the back of the event queue & ensure it occurs last.

def my_method (self):

self.some_signal.emit()

self.some_other_signal.emit()

QTimer.singleShot( 0 , do_something_here) ①

①This will be executed after the signal’s effects.

j

This technique only guarantees that the do_something_here

function executes after the preceding signals, not any

downstream effects of them. Don’t be tempted to increase the

value of msecs to work around this, as this makes your

application dependent on system timings.

'PyQt5_' 카테고리의 다른 글

Extending Signals  (0) 2023.03.13
Extending Signals  (0) 2023.03.13
Plotting with Matplotlib.  (0) 2023.03.13
Plotting with PyQtGraph  (0) 2023.03.13
Running external commands & processes  (0) 2023.03.13

댓글