Make a simple stopwatch stoppable
up vote
1
down vote
favorite
I'm writing a simple stopwatch with python (using pyqt5).
So far, start/pause/resume functions are working fine but the problem is when I stop the counter and need to start from 0 a thread can't be started again I tried the subclass from here but it's not working.
import threading
from PyQt5 import QtWidgets
from stpw_ui import Ui_MainWindow
from time import sleep
# code snippet from stack overflow to stop a thread
class StoppableThread(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# buttons' actions
self.ui.start.clicked.connect(self.stopwatch)
self.ui.pause.clicked.connect(self.pse)
self.ui.stop.clicked.connect(self.stp)
self.ui.resume.clicked.connect(self.res)
# self.ui.reset.clicked.connect(self.rst)
self.t = StoppableThread(target=self.strt)
def UpdateSec(self,s):
self.ui.seconds.display(s)
def UpdateMin(self,m):
self.ui.minutes.display(m)
def stopwatch(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.pause = False
self.t.start()
pause = False
second = 0
minute = 0
def setpause(self,x):
self.pause = x
# start
def strt(self):
if (self.pause is True):
sleep(0.1)
while self.second <= 59 and self.pause == False:
self.UpdateSec(self.second)
self.second += 1
sleep(1)
if self.second==59:
self.minute += 1
self.UpdateMin(self.minute)
self.second = 0
self.strt()
# pause
def pse(self):
self.ui.stacked_buttons.setCurrentIndex(2)
self.setpause(True)
# stop
def stp(self):
self.setpause(True)
self.ui.stacked_buttons.setCurrentIndex(0)
self.t.stop()
# resume
def res(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.setpause(False)
# reset / ignore it for now
# def rst(self):
# self.ui.stacked_buttons.setCurrentIndex(0)
# self.setpause(False)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
So:
- How to make the stop button works? (what I'm doing wrong here?)
- Is there a better/simple approach to make a stopwatch? because I feel like I'm over-complicating it.
The GUI (stpw_ui.py) file is available at https://www.filedropper.com/stpwui
python python-3.x pyqt pyqt5
New contributor
add a comment |
up vote
1
down vote
favorite
I'm writing a simple stopwatch with python (using pyqt5).
So far, start/pause/resume functions are working fine but the problem is when I stop the counter and need to start from 0 a thread can't be started again I tried the subclass from here but it's not working.
import threading
from PyQt5 import QtWidgets
from stpw_ui import Ui_MainWindow
from time import sleep
# code snippet from stack overflow to stop a thread
class StoppableThread(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# buttons' actions
self.ui.start.clicked.connect(self.stopwatch)
self.ui.pause.clicked.connect(self.pse)
self.ui.stop.clicked.connect(self.stp)
self.ui.resume.clicked.connect(self.res)
# self.ui.reset.clicked.connect(self.rst)
self.t = StoppableThread(target=self.strt)
def UpdateSec(self,s):
self.ui.seconds.display(s)
def UpdateMin(self,m):
self.ui.minutes.display(m)
def stopwatch(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.pause = False
self.t.start()
pause = False
second = 0
minute = 0
def setpause(self,x):
self.pause = x
# start
def strt(self):
if (self.pause is True):
sleep(0.1)
while self.second <= 59 and self.pause == False:
self.UpdateSec(self.second)
self.second += 1
sleep(1)
if self.second==59:
self.minute += 1
self.UpdateMin(self.minute)
self.second = 0
self.strt()
# pause
def pse(self):
self.ui.stacked_buttons.setCurrentIndex(2)
self.setpause(True)
# stop
def stp(self):
self.setpause(True)
self.ui.stacked_buttons.setCurrentIndex(0)
self.t.stop()
# resume
def res(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.setpause(False)
# reset / ignore it for now
# def rst(self):
# self.ui.stacked_buttons.setCurrentIndex(0)
# self.setpause(False)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
So:
- How to make the stop button works? (what I'm doing wrong here?)
- Is there a better/simple approach to make a stopwatch? because I feel like I'm over-complicating it.
The GUI (stpw_ui.py) file is available at https://www.filedropper.com/stpwui
python python-3.x pyqt pyqt5
New contributor
please share the stpw_ui.py
– eyllanesc
Nov 21 at 5:39
@eyllanesc done!
– ImadX122
Nov 21 at 6:42
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I'm writing a simple stopwatch with python (using pyqt5).
So far, start/pause/resume functions are working fine but the problem is when I stop the counter and need to start from 0 a thread can't be started again I tried the subclass from here but it's not working.
import threading
from PyQt5 import QtWidgets
from stpw_ui import Ui_MainWindow
from time import sleep
# code snippet from stack overflow to stop a thread
class StoppableThread(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# buttons' actions
self.ui.start.clicked.connect(self.stopwatch)
self.ui.pause.clicked.connect(self.pse)
self.ui.stop.clicked.connect(self.stp)
self.ui.resume.clicked.connect(self.res)
# self.ui.reset.clicked.connect(self.rst)
self.t = StoppableThread(target=self.strt)
def UpdateSec(self,s):
self.ui.seconds.display(s)
def UpdateMin(self,m):
self.ui.minutes.display(m)
def stopwatch(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.pause = False
self.t.start()
pause = False
second = 0
minute = 0
def setpause(self,x):
self.pause = x
# start
def strt(self):
if (self.pause is True):
sleep(0.1)
while self.second <= 59 and self.pause == False:
self.UpdateSec(self.second)
self.second += 1
sleep(1)
if self.second==59:
self.minute += 1
self.UpdateMin(self.minute)
self.second = 0
self.strt()
# pause
def pse(self):
self.ui.stacked_buttons.setCurrentIndex(2)
self.setpause(True)
# stop
def stp(self):
self.setpause(True)
self.ui.stacked_buttons.setCurrentIndex(0)
self.t.stop()
# resume
def res(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.setpause(False)
# reset / ignore it for now
# def rst(self):
# self.ui.stacked_buttons.setCurrentIndex(0)
# self.setpause(False)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
So:
- How to make the stop button works? (what I'm doing wrong here?)
- Is there a better/simple approach to make a stopwatch? because I feel like I'm over-complicating it.
The GUI (stpw_ui.py) file is available at https://www.filedropper.com/stpwui
python python-3.x pyqt pyqt5
New contributor
I'm writing a simple stopwatch with python (using pyqt5).
So far, start/pause/resume functions are working fine but the problem is when I stop the counter and need to start from 0 a thread can't be started again I tried the subclass from here but it's not working.
import threading
from PyQt5 import QtWidgets
from stpw_ui import Ui_MainWindow
from time import sleep
# code snippet from stack overflow to stop a thread
class StoppableThread(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# buttons' actions
self.ui.start.clicked.connect(self.stopwatch)
self.ui.pause.clicked.connect(self.pse)
self.ui.stop.clicked.connect(self.stp)
self.ui.resume.clicked.connect(self.res)
# self.ui.reset.clicked.connect(self.rst)
self.t = StoppableThread(target=self.strt)
def UpdateSec(self,s):
self.ui.seconds.display(s)
def UpdateMin(self,m):
self.ui.minutes.display(m)
def stopwatch(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.pause = False
self.t.start()
pause = False
second = 0
minute = 0
def setpause(self,x):
self.pause = x
# start
def strt(self):
if (self.pause is True):
sleep(0.1)
while self.second <= 59 and self.pause == False:
self.UpdateSec(self.second)
self.second += 1
sleep(1)
if self.second==59:
self.minute += 1
self.UpdateMin(self.minute)
self.second = 0
self.strt()
# pause
def pse(self):
self.ui.stacked_buttons.setCurrentIndex(2)
self.setpause(True)
# stop
def stp(self):
self.setpause(True)
self.ui.stacked_buttons.setCurrentIndex(0)
self.t.stop()
# resume
def res(self):
self.ui.stacked_buttons.setCurrentIndex(1)
self.setpause(False)
# reset / ignore it for now
# def rst(self):
# self.ui.stacked_buttons.setCurrentIndex(0)
# self.setpause(False)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
So:
- How to make the stop button works? (what I'm doing wrong here?)
- Is there a better/simple approach to make a stopwatch? because I feel like I'm over-complicating it.
The GUI (stpw_ui.py) file is available at https://www.filedropper.com/stpwui
python python-3.x pyqt pyqt5
python python-3.x pyqt pyqt5
New contributor
New contributor
edited Nov 21 at 7:19
eyllanesc
69k93052
69k93052
New contributor
asked Nov 21 at 5:33
ImadX122
85
85
New contributor
New contributor
please share the stpw_ui.py
– eyllanesc
Nov 21 at 5:39
@eyllanesc done!
– ImadX122
Nov 21 at 6:42
add a comment |
please share the stpw_ui.py
– eyllanesc
Nov 21 at 5:39
@eyllanesc done!
– ImadX122
Nov 21 at 6:42
please share the stpw_ui.py
– eyllanesc
Nov 21 at 5:39
please share the stpw_ui.py
– eyllanesc
Nov 21 at 5:39
@eyllanesc done!
– ImadX122
Nov 21 at 6:42
@eyllanesc done!
– ImadX122
Nov 21 at 6:42
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
accepted
Do not use sleep in a GUI because you can freeze the GUI. On the other hand using a thread is too much for this question, in a GUI the use of thread is only justified if the task is heavy, but increasing a pair of data every second is not a heavy task.
Instead, you must use QTimer to perform repetitive tasks and QTime to get the elapsed time.
For the logic a state machine must be implemented, in this case it will be StopWatch that will emit the necessary signals to notify the changes to the GUI.
from PyQt5 import QtCore, QtWidgets
from stpw_ui import Ui_MainWindow
class State:
STOPPED = 0
PAUSE = 1
RUNNING = 1 << 1
class StopWatch(QtCore.QObject, State):
State = State
QtCore.Q_ENUMS(State)
secondChanged = QtCore.pyqtSignal(int)
minuteChanged = QtCore.pyqtSignal(int)
stateChanged = QtCore.pyqtSignal(State)
def __init__(self, parent=None):
super(StopWatch, self).__init__(parent)
self._current_state = State.STOPPED
self._time = QtCore.QTime()
self._timer = QtCore.QTimer(self, interval=100, timeout=self.on_timeout)
self._delta = 0
self._seconds = 0
self._minutes = 0
def setCurrentState(self, state):
self._current_state = state
self.stateChanged.emit(state)
@QtCore.pyqtSlot()
def start(self):
self._delta = 0
self._timer.start()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def stop(self):
if self._current_state != State.STOPPED:
self._timer.stop()
self.setCurrentState(State.STOPPED)
@QtCore.pyqtSlot()
def pause(self):
if self._current_state == State.RUNNING:
self._timer.stop()
self.setCurrentState(State.PAUSE)
self._delta += self._time.elapsed()
@QtCore.pyqtSlot()
def resume(self):
if self._current_state == State.PAUSE:
self._timer.start()
self._time = QtCore.QTime()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def on_timeout(self):
t = QtCore.QTime.fromMSecsSinceStartOfDay(self._delta + self._time.elapsed())
s, m = t.second(), t.minute()
if self._seconds != s:
self._seconds = s
self.secondChanged.emit(s)
if self._minutes != m:
self._minutes = m
self.minuteChanged.emit(m)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self._stop_watch = StopWatch(self)
self.start.clicked.connect(self._stop_watch.start)
self.pause.clicked.connect(self._stop_watch.pause)
self.stop.clicked.connect(self._stop_watch.stop)
self.resume.clicked.connect(self._stop_watch.resume)
self._stop_watch.secondChanged.connect(self.seconds.display)
self._stop_watch.minuteChanged.connect(self.minutes.display)
self._stop_watch.stateChanged.connect(self.on_stateChanged)
@QtCore.pyqtSlot(StopWatch.State)
def on_stateChanged(self, state):
if state == StopWatch.RUNNING:
self.stacked_buttons.setCurrentIndex(1)
elif state == StopWatch.PAUSE:
self.stacked_buttons.setCurrentIndex(2)
elif state == StopWatch.STOPPED:
self.stacked_buttons.setCurrentIndex(0)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
accepted
Do not use sleep in a GUI because you can freeze the GUI. On the other hand using a thread is too much for this question, in a GUI the use of thread is only justified if the task is heavy, but increasing a pair of data every second is not a heavy task.
Instead, you must use QTimer to perform repetitive tasks and QTime to get the elapsed time.
For the logic a state machine must be implemented, in this case it will be StopWatch that will emit the necessary signals to notify the changes to the GUI.
from PyQt5 import QtCore, QtWidgets
from stpw_ui import Ui_MainWindow
class State:
STOPPED = 0
PAUSE = 1
RUNNING = 1 << 1
class StopWatch(QtCore.QObject, State):
State = State
QtCore.Q_ENUMS(State)
secondChanged = QtCore.pyqtSignal(int)
minuteChanged = QtCore.pyqtSignal(int)
stateChanged = QtCore.pyqtSignal(State)
def __init__(self, parent=None):
super(StopWatch, self).__init__(parent)
self._current_state = State.STOPPED
self._time = QtCore.QTime()
self._timer = QtCore.QTimer(self, interval=100, timeout=self.on_timeout)
self._delta = 0
self._seconds = 0
self._minutes = 0
def setCurrentState(self, state):
self._current_state = state
self.stateChanged.emit(state)
@QtCore.pyqtSlot()
def start(self):
self._delta = 0
self._timer.start()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def stop(self):
if self._current_state != State.STOPPED:
self._timer.stop()
self.setCurrentState(State.STOPPED)
@QtCore.pyqtSlot()
def pause(self):
if self._current_state == State.RUNNING:
self._timer.stop()
self.setCurrentState(State.PAUSE)
self._delta += self._time.elapsed()
@QtCore.pyqtSlot()
def resume(self):
if self._current_state == State.PAUSE:
self._timer.start()
self._time = QtCore.QTime()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def on_timeout(self):
t = QtCore.QTime.fromMSecsSinceStartOfDay(self._delta + self._time.elapsed())
s, m = t.second(), t.minute()
if self._seconds != s:
self._seconds = s
self.secondChanged.emit(s)
if self._minutes != m:
self._minutes = m
self.minuteChanged.emit(m)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self._stop_watch = StopWatch(self)
self.start.clicked.connect(self._stop_watch.start)
self.pause.clicked.connect(self._stop_watch.pause)
self.stop.clicked.connect(self._stop_watch.stop)
self.resume.clicked.connect(self._stop_watch.resume)
self._stop_watch.secondChanged.connect(self.seconds.display)
self._stop_watch.minuteChanged.connect(self.minutes.display)
self._stop_watch.stateChanged.connect(self.on_stateChanged)
@QtCore.pyqtSlot(StopWatch.State)
def on_stateChanged(self, state):
if state == StopWatch.RUNNING:
self.stacked_buttons.setCurrentIndex(1)
elif state == StopWatch.PAUSE:
self.stacked_buttons.setCurrentIndex(2)
elif state == StopWatch.STOPPED:
self.stacked_buttons.setCurrentIndex(0)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57
add a comment |
up vote
0
down vote
accepted
Do not use sleep in a GUI because you can freeze the GUI. On the other hand using a thread is too much for this question, in a GUI the use of thread is only justified if the task is heavy, but increasing a pair of data every second is not a heavy task.
Instead, you must use QTimer to perform repetitive tasks and QTime to get the elapsed time.
For the logic a state machine must be implemented, in this case it will be StopWatch that will emit the necessary signals to notify the changes to the GUI.
from PyQt5 import QtCore, QtWidgets
from stpw_ui import Ui_MainWindow
class State:
STOPPED = 0
PAUSE = 1
RUNNING = 1 << 1
class StopWatch(QtCore.QObject, State):
State = State
QtCore.Q_ENUMS(State)
secondChanged = QtCore.pyqtSignal(int)
minuteChanged = QtCore.pyqtSignal(int)
stateChanged = QtCore.pyqtSignal(State)
def __init__(self, parent=None):
super(StopWatch, self).__init__(parent)
self._current_state = State.STOPPED
self._time = QtCore.QTime()
self._timer = QtCore.QTimer(self, interval=100, timeout=self.on_timeout)
self._delta = 0
self._seconds = 0
self._minutes = 0
def setCurrentState(self, state):
self._current_state = state
self.stateChanged.emit(state)
@QtCore.pyqtSlot()
def start(self):
self._delta = 0
self._timer.start()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def stop(self):
if self._current_state != State.STOPPED:
self._timer.stop()
self.setCurrentState(State.STOPPED)
@QtCore.pyqtSlot()
def pause(self):
if self._current_state == State.RUNNING:
self._timer.stop()
self.setCurrentState(State.PAUSE)
self._delta += self._time.elapsed()
@QtCore.pyqtSlot()
def resume(self):
if self._current_state == State.PAUSE:
self._timer.start()
self._time = QtCore.QTime()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def on_timeout(self):
t = QtCore.QTime.fromMSecsSinceStartOfDay(self._delta + self._time.elapsed())
s, m = t.second(), t.minute()
if self._seconds != s:
self._seconds = s
self.secondChanged.emit(s)
if self._minutes != m:
self._minutes = m
self.minuteChanged.emit(m)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self._stop_watch = StopWatch(self)
self.start.clicked.connect(self._stop_watch.start)
self.pause.clicked.connect(self._stop_watch.pause)
self.stop.clicked.connect(self._stop_watch.stop)
self.resume.clicked.connect(self._stop_watch.resume)
self._stop_watch.secondChanged.connect(self.seconds.display)
self._stop_watch.minuteChanged.connect(self.minutes.display)
self._stop_watch.stateChanged.connect(self.on_stateChanged)
@QtCore.pyqtSlot(StopWatch.State)
def on_stateChanged(self, state):
if state == StopWatch.RUNNING:
self.stacked_buttons.setCurrentIndex(1)
elif state == StopWatch.PAUSE:
self.stacked_buttons.setCurrentIndex(2)
elif state == StopWatch.STOPPED:
self.stacked_buttons.setCurrentIndex(0)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57
add a comment |
up vote
0
down vote
accepted
up vote
0
down vote
accepted
Do not use sleep in a GUI because you can freeze the GUI. On the other hand using a thread is too much for this question, in a GUI the use of thread is only justified if the task is heavy, but increasing a pair of data every second is not a heavy task.
Instead, you must use QTimer to perform repetitive tasks and QTime to get the elapsed time.
For the logic a state machine must be implemented, in this case it will be StopWatch that will emit the necessary signals to notify the changes to the GUI.
from PyQt5 import QtCore, QtWidgets
from stpw_ui import Ui_MainWindow
class State:
STOPPED = 0
PAUSE = 1
RUNNING = 1 << 1
class StopWatch(QtCore.QObject, State):
State = State
QtCore.Q_ENUMS(State)
secondChanged = QtCore.pyqtSignal(int)
minuteChanged = QtCore.pyqtSignal(int)
stateChanged = QtCore.pyqtSignal(State)
def __init__(self, parent=None):
super(StopWatch, self).__init__(parent)
self._current_state = State.STOPPED
self._time = QtCore.QTime()
self._timer = QtCore.QTimer(self, interval=100, timeout=self.on_timeout)
self._delta = 0
self._seconds = 0
self._minutes = 0
def setCurrentState(self, state):
self._current_state = state
self.stateChanged.emit(state)
@QtCore.pyqtSlot()
def start(self):
self._delta = 0
self._timer.start()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def stop(self):
if self._current_state != State.STOPPED:
self._timer.stop()
self.setCurrentState(State.STOPPED)
@QtCore.pyqtSlot()
def pause(self):
if self._current_state == State.RUNNING:
self._timer.stop()
self.setCurrentState(State.PAUSE)
self._delta += self._time.elapsed()
@QtCore.pyqtSlot()
def resume(self):
if self._current_state == State.PAUSE:
self._timer.start()
self._time = QtCore.QTime()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def on_timeout(self):
t = QtCore.QTime.fromMSecsSinceStartOfDay(self._delta + self._time.elapsed())
s, m = t.second(), t.minute()
if self._seconds != s:
self._seconds = s
self.secondChanged.emit(s)
if self._minutes != m:
self._minutes = m
self.minuteChanged.emit(m)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self._stop_watch = StopWatch(self)
self.start.clicked.connect(self._stop_watch.start)
self.pause.clicked.connect(self._stop_watch.pause)
self.stop.clicked.connect(self._stop_watch.stop)
self.resume.clicked.connect(self._stop_watch.resume)
self._stop_watch.secondChanged.connect(self.seconds.display)
self._stop_watch.minuteChanged.connect(self.minutes.display)
self._stop_watch.stateChanged.connect(self.on_stateChanged)
@QtCore.pyqtSlot(StopWatch.State)
def on_stateChanged(self, state):
if state == StopWatch.RUNNING:
self.stacked_buttons.setCurrentIndex(1)
elif state == StopWatch.PAUSE:
self.stacked_buttons.setCurrentIndex(2)
elif state == StopWatch.STOPPED:
self.stacked_buttons.setCurrentIndex(0)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Do not use sleep in a GUI because you can freeze the GUI. On the other hand using a thread is too much for this question, in a GUI the use of thread is only justified if the task is heavy, but increasing a pair of data every second is not a heavy task.
Instead, you must use QTimer to perform repetitive tasks and QTime to get the elapsed time.
For the logic a state machine must be implemented, in this case it will be StopWatch that will emit the necessary signals to notify the changes to the GUI.
from PyQt5 import QtCore, QtWidgets
from stpw_ui import Ui_MainWindow
class State:
STOPPED = 0
PAUSE = 1
RUNNING = 1 << 1
class StopWatch(QtCore.QObject, State):
State = State
QtCore.Q_ENUMS(State)
secondChanged = QtCore.pyqtSignal(int)
minuteChanged = QtCore.pyqtSignal(int)
stateChanged = QtCore.pyqtSignal(State)
def __init__(self, parent=None):
super(StopWatch, self).__init__(parent)
self._current_state = State.STOPPED
self._time = QtCore.QTime()
self._timer = QtCore.QTimer(self, interval=100, timeout=self.on_timeout)
self._delta = 0
self._seconds = 0
self._minutes = 0
def setCurrentState(self, state):
self._current_state = state
self.stateChanged.emit(state)
@QtCore.pyqtSlot()
def start(self):
self._delta = 0
self._timer.start()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def stop(self):
if self._current_state != State.STOPPED:
self._timer.stop()
self.setCurrentState(State.STOPPED)
@QtCore.pyqtSlot()
def pause(self):
if self._current_state == State.RUNNING:
self._timer.stop()
self.setCurrentState(State.PAUSE)
self._delta += self._time.elapsed()
@QtCore.pyqtSlot()
def resume(self):
if self._current_state == State.PAUSE:
self._timer.start()
self._time = QtCore.QTime()
self._time.start()
self.setCurrentState(State.RUNNING)
@QtCore.pyqtSlot()
def on_timeout(self):
t = QtCore.QTime.fromMSecsSinceStartOfDay(self._delta + self._time.elapsed())
s, m = t.second(), t.minute()
if self._seconds != s:
self._seconds = s
self.secondChanged.emit(s)
if self._minutes != m:
self._minutes = m
self.minuteChanged.emit(m)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self._stop_watch = StopWatch(self)
self.start.clicked.connect(self._stop_watch.start)
self.pause.clicked.connect(self._stop_watch.pause)
self.stop.clicked.connect(self._stop_watch.stop)
self.resume.clicked.connect(self._stop_watch.resume)
self._stop_watch.secondChanged.connect(self.seconds.display)
self._stop_watch.minuteChanged.connect(self.minutes.display)
self._stop_watch.stateChanged.connect(self.on_stateChanged)
@QtCore.pyqtSlot(StopWatch.State)
def on_stateChanged(self, state):
if state == StopWatch.RUNNING:
self.stacked_buttons.setCurrentIndex(1)
elif state == StopWatch.PAUSE:
self.stacked_buttons.setCurrentIndex(2)
elif state == StopWatch.STOPPED:
self.stacked_buttons.setCurrentIndex(0)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
answered Nov 21 at 7:12
eyllanesc
69k93052
69k93052
Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57
add a comment |
Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57
Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57
Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57
add a comment |
ImadX122 is a new contributor. Be nice, and check out our Code of Conduct.
ImadX122 is a new contributor. Be nice, and check out our Code of Conduct.
ImadX122 is a new contributor. Be nice, and check out our Code of Conduct.
ImadX122 is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53405789%2fmake-a-simple-stopwatch-stoppable%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
please share the stpw_ui.py
– eyllanesc
Nov 21 at 5:39
@eyllanesc done!
– ImadX122
Nov 21 at 6:42