Stopwatch getting faster every click of 'Start' button - python

from PyQt5 import uic
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication([])
window = uic.loadUi("exercise3.ui")
timer = QTimer()
def start():
timer.start(10)
timer.timeout.connect(updateDisplay)
time = 0
def updateDisplay():
global time
time += 1
text = str(time/100)
window.timeDisplay.setText(text)
def stop():
timer.stop()
window.startButton.clicked.connect(start)
window.stopButton.clicked.connect(stop)
window.show()
app.exec_()
Hi, super beginner here, not sure why, but every time I press the start button in the GUI, the stopwatch seems to get faster and faster, almost as if the interval is changing. Not quite sure what's going on, would appreciate if someone could help, thank you!

I seem to have solved it! The 'timeout.connect()' call should be outside of the start() slot. Somehow, when it was in the start() slot, it seems like the signal was connected multiple times to the same slot, resulting in the slot being called multiples times too, making it accelerate every time it was called.

Related

PyQt hiding widget for set period of time [duplicate]

I can't use time.sleep in my pyqt application because that freezes the GUI thread, so the GUI will be completely frozen during this time.I have been looking for a way to handle this.
I tried to use QTimer, but it seemed like they need to be linked to another function? Like wait ten seconds then run some function. Is there a way to just have it wait then continue with the current function?
def num(self):
for i in range(1,999):
print i
#Add some sleep here
def testSleep(self):
QtCore.QTimer.singleShot(2000, self.num)
Actually i was looking for time.sleep alternative to use in pyqt without using any thread concepts.
And the solution i figured out is:
from PyQt4 import QtTest
QtTest.QTest.qWait(msecs)
This works similar to time.sleep making GUI responsive.
Thankyou for your answers.
Maybe it could be done better but you can always use singleShot to run function with delay, and lambda to run function with argument.
import sys
from PyQt4 import QtGui, QtCore
#def num(self, i):
def num(i):
print i
i += 1
if i < 999:
# run again after 2000ms with argument
QtCore.QTimer.singleShot(2000, lambda:num(i))
#QtCore.QTimer.singleShot(2000, lambda:self.num(i))
app = QtGui.QApplication(sys.argv)
# run first time with start argument
num(1)
#QtCore.QTimer.singleShot(2000, lambda:num(1))
sys.exit(app.exec_())
Another option would be to process Qt events while waiting:
def num():
for i in range(1, 999):
print(i)
# Sleep five seconds in total
for _ in range(5 * 10):
# Process events between short sleep periods
QtWidgets.QApplication.processEvents()
time.sleep(0.1)
You cannot use time.sleep in the pyqt main event loop as it would stop the GUI event loop from responding.
A solution in pyqt could look like this, using QTimer
import sys
from PyQt4 import QtGui, QtCore
application = QtGui.QApplication(sys.argv)
i=0
timer = QtCore.QTimer()
def num():
global i, timer
if i <999:
print ( i )
i += 1
else:
timer.stop()
timer.timeout.connect(num)
timer.start(2000)
sys.exit(application.exec_())
I believe you are asking how to keep the GUI responsive if num() takes several seconds to run? You have two options:
if num() consists of many small chunks of "work", you can call application.processEvents() between the chunks, this will allow the GUI to respond to events. An easy situation to deal with is when most of the num() time is spent in a loop, then at the start or end of each iteration, call application.processEvents(). In your real application, if you don't have access to application, import qApp from PyQt4.
the better approach is to execute num() in a separate thread. There are many examples of this on SO (like this one). One way of doing that is
instantiate a QThread,
define a class (say NumberCruncher) that derives from QObject and defines num(self) and defines a signal 'done' emitted by num() before returning
call numberCruncher.moveToThread(thread)
connect the thread started signal to num
start the thread

I cant change button position in pyqt5 [duplicate]

I can't use time.sleep in my pyqt application because that freezes the GUI thread, so the GUI will be completely frozen during this time.I have been looking for a way to handle this.
I tried to use QTimer, but it seemed like they need to be linked to another function? Like wait ten seconds then run some function. Is there a way to just have it wait then continue with the current function?
def num(self):
for i in range(1,999):
print i
#Add some sleep here
def testSleep(self):
QtCore.QTimer.singleShot(2000, self.num)
Actually i was looking for time.sleep alternative to use in pyqt without using any thread concepts.
And the solution i figured out is:
from PyQt4 import QtTest
QtTest.QTest.qWait(msecs)
This works similar to time.sleep making GUI responsive.
Thankyou for your answers.
Maybe it could be done better but you can always use singleShot to run function with delay, and lambda to run function with argument.
import sys
from PyQt4 import QtGui, QtCore
#def num(self, i):
def num(i):
print i
i += 1
if i < 999:
# run again after 2000ms with argument
QtCore.QTimer.singleShot(2000, lambda:num(i))
#QtCore.QTimer.singleShot(2000, lambda:self.num(i))
app = QtGui.QApplication(sys.argv)
# run first time with start argument
num(1)
#QtCore.QTimer.singleShot(2000, lambda:num(1))
sys.exit(app.exec_())
Another option would be to process Qt events while waiting:
def num():
for i in range(1, 999):
print(i)
# Sleep five seconds in total
for _ in range(5 * 10):
# Process events between short sleep periods
QtWidgets.QApplication.processEvents()
time.sleep(0.1)
You cannot use time.sleep in the pyqt main event loop as it would stop the GUI event loop from responding.
A solution in pyqt could look like this, using QTimer
import sys
from PyQt4 import QtGui, QtCore
application = QtGui.QApplication(sys.argv)
i=0
timer = QtCore.QTimer()
def num():
global i, timer
if i <999:
print ( i )
i += 1
else:
timer.stop()
timer.timeout.connect(num)
timer.start(2000)
sys.exit(application.exec_())
I believe you are asking how to keep the GUI responsive if num() takes several seconds to run? You have two options:
if num() consists of many small chunks of "work", you can call application.processEvents() between the chunks, this will allow the GUI to respond to events. An easy situation to deal with is when most of the num() time is spent in a loop, then at the start or end of each iteration, call application.processEvents(). In your real application, if you don't have access to application, import qApp from PyQt4.
the better approach is to execute num() in a separate thread. There are many examples of this on SO (like this one). One way of doing that is
instantiate a QThread,
define a class (say NumberCruncher) that derives from QObject and defines num(self) and defines a signal 'done' emitted by num() before returning
call numberCruncher.moveToThread(thread)
connect the thread started signal to num
start the thread

Loading bar job doesn't render till job is complete PyQt5

I have created a UI using PyQt5 that contains a progress bar. I have coded this progress bar in python so that it increases to 99% in real time. The problem I am facing is that the window does not load until the job is complete. I have read upon similar posts which talk about threading and I cannot possibly grasp anything from it. I would appreciate if someone could explain to me a solution and if it does require threading, an aspect I am yet to learn, please explain it to me in laymans term.
import sys, os, sqlite3
import random, datetime
from PyQt5 import QtCore, QtGui, uic
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton,
QMessageBox, QProgressBar, QSplashScreen
import sqlite3
import time
window2 = uic.loadUiType("login_loadingbar.ui")[0]
class LoadingBar(QtWidgets.QMainWindow, window2):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
#title
self.setWindowTitle('Loading')
#makes progress bar go from 0-100, time scaled
def progress(self):
for i in range(100):
time.sleep(0.1)
self.login_progressBar.setValue(i)
app = QApplication(sys.argv)
w2 = LoadingBar(None)
w2.show()
w2.progress()
app.exec_()
When you create gui application you have one thread, in this thread there's thing called event loop - its essentially while true loop that handles events - redraws widgets when necessary, dispatches keyboard and mouse input to related widgets.
Since you have only one thread you can only do one thing at a time, so when you do long operation like time.sleep(), event loop is frozen - no widgets gets redrawn, no inputs handled until it completes and next iteration of event loop reached.
You can create second thread and move operation there or in simple cases when operation can be split into pieces - process events in event loop in between pieces:
for i in range(100):
time.sleep(0.1)
self.login_progressBar.setValue(i)
QtWidgets.QApplication.processEvents()
This way event loop kinda works, but application is not 100% responsive, because every time.sleep(0.1) freezes it, so mouse clicks and other events may not be handled.

PyQt5 text label freezing during loop display [duplicate]

I can't use time.sleep in my pyqt application because that freezes the GUI thread, so the GUI will be completely frozen during this time.I have been looking for a way to handle this.
I tried to use QTimer, but it seemed like they need to be linked to another function? Like wait ten seconds then run some function. Is there a way to just have it wait then continue with the current function?
def num(self):
for i in range(1,999):
print i
#Add some sleep here
def testSleep(self):
QtCore.QTimer.singleShot(2000, self.num)
Actually i was looking for time.sleep alternative to use in pyqt without using any thread concepts.
And the solution i figured out is:
from PyQt4 import QtTest
QtTest.QTest.qWait(msecs)
This works similar to time.sleep making GUI responsive.
Thankyou for your answers.
Maybe it could be done better but you can always use singleShot to run function with delay, and lambda to run function with argument.
import sys
from PyQt4 import QtGui, QtCore
#def num(self, i):
def num(i):
print i
i += 1
if i < 999:
# run again after 2000ms with argument
QtCore.QTimer.singleShot(2000, lambda:num(i))
#QtCore.QTimer.singleShot(2000, lambda:self.num(i))
app = QtGui.QApplication(sys.argv)
# run first time with start argument
num(1)
#QtCore.QTimer.singleShot(2000, lambda:num(1))
sys.exit(app.exec_())
Another option would be to process Qt events while waiting:
def num():
for i in range(1, 999):
print(i)
# Sleep five seconds in total
for _ in range(5 * 10):
# Process events between short sleep periods
QtWidgets.QApplication.processEvents()
time.sleep(0.1)
You cannot use time.sleep in the pyqt main event loop as it would stop the GUI event loop from responding.
A solution in pyqt could look like this, using QTimer
import sys
from PyQt4 import QtGui, QtCore
application = QtGui.QApplication(sys.argv)
i=0
timer = QtCore.QTimer()
def num():
global i, timer
if i <999:
print ( i )
i += 1
else:
timer.stop()
timer.timeout.connect(num)
timer.start(2000)
sys.exit(application.exec_())
I believe you are asking how to keep the GUI responsive if num() takes several seconds to run? You have two options:
if num() consists of many small chunks of "work", you can call application.processEvents() between the chunks, this will allow the GUI to respond to events. An easy situation to deal with is when most of the num() time is spent in a loop, then at the start or end of each iteration, call application.processEvents(). In your real application, if you don't have access to application, import qApp from PyQt4.
the better approach is to execute num() in a separate thread. There are many examples of this on SO (like this one). One way of doing that is
instantiate a QThread,
define a class (say NumberCruncher) that derives from QObject and defines num(self) and defines a signal 'done' emitted by num() before returning
call numberCruncher.moveToThread(thread)
connect the thread started signal to num
start the thread

PyQt5: stops rendering when window is out of focus [duplicate]

I can't use time.sleep in my pyqt application because that freezes the GUI thread, so the GUI will be completely frozen during this time.I have been looking for a way to handle this.
I tried to use QTimer, but it seemed like they need to be linked to another function? Like wait ten seconds then run some function. Is there a way to just have it wait then continue with the current function?
def num(self):
for i in range(1,999):
print i
#Add some sleep here
def testSleep(self):
QtCore.QTimer.singleShot(2000, self.num)
Actually i was looking for time.sleep alternative to use in pyqt without using any thread concepts.
And the solution i figured out is:
from PyQt4 import QtTest
QtTest.QTest.qWait(msecs)
This works similar to time.sleep making GUI responsive.
Thankyou for your answers.
Maybe it could be done better but you can always use singleShot to run function with delay, and lambda to run function with argument.
import sys
from PyQt4 import QtGui, QtCore
#def num(self, i):
def num(i):
print i
i += 1
if i < 999:
# run again after 2000ms with argument
QtCore.QTimer.singleShot(2000, lambda:num(i))
#QtCore.QTimer.singleShot(2000, lambda:self.num(i))
app = QtGui.QApplication(sys.argv)
# run first time with start argument
num(1)
#QtCore.QTimer.singleShot(2000, lambda:num(1))
sys.exit(app.exec_())
Another option would be to process Qt events while waiting:
def num():
for i in range(1, 999):
print(i)
# Sleep five seconds in total
for _ in range(5 * 10):
# Process events between short sleep periods
QtWidgets.QApplication.processEvents()
time.sleep(0.1)
You cannot use time.sleep in the pyqt main event loop as it would stop the GUI event loop from responding.
A solution in pyqt could look like this, using QTimer
import sys
from PyQt4 import QtGui, QtCore
application = QtGui.QApplication(sys.argv)
i=0
timer = QtCore.QTimer()
def num():
global i, timer
if i <999:
print ( i )
i += 1
else:
timer.stop()
timer.timeout.connect(num)
timer.start(2000)
sys.exit(application.exec_())
I believe you are asking how to keep the GUI responsive if num() takes several seconds to run? You have two options:
if num() consists of many small chunks of "work", you can call application.processEvents() between the chunks, this will allow the GUI to respond to events. An easy situation to deal with is when most of the num() time is spent in a loop, then at the start or end of each iteration, call application.processEvents(). In your real application, if you don't have access to application, import qApp from PyQt4.
the better approach is to execute num() in a separate thread. There are many examples of this on SO (like this one). One way of doing that is
instantiate a QThread,
define a class (say NumberCruncher) that derives from QObject and defines num(self) and defines a signal 'done' emitted by num() before returning
call numberCruncher.moveToThread(thread)
connect the thread started signal to num
start the thread

Categories