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:




  1. How to make the stop button works? (what I'm doing wrong here?)

  2. 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










share|improve this question









New contributor




ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • please share the stpw_ui.py
    – eyllanesc
    Nov 21 at 5:39










  • @eyllanesc done!
    – ImadX122
    Nov 21 at 6:42















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:




  1. How to make the stop button works? (what I'm doing wrong here?)

  2. 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










share|improve this question









New contributor




ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • please share the stpw_ui.py
    – eyllanesc
    Nov 21 at 5:39










  • @eyllanesc done!
    – ImadX122
    Nov 21 at 6:42













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:




  1. How to make the stop button works? (what I'm doing wrong here?)

  2. 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










share|improve this question









New contributor




ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











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:




  1. How to make the stop button works? (what I'm doing wrong here?)

  2. 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






share|improve this question









New contributor




ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Nov 21 at 7:19









eyllanesc

69k93052




69k93052






New contributor




ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Nov 21 at 5:33









ImadX122

85




85




New contributor




ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






ImadX122 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • 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










  • @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












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_())





share|improve this answer





















  • Nice job matching the OPs skill level.
    – MikeyB
    Nov 22 at 1:57











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






ImadX122 is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















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

























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_())





share|improve this answer





















  • Nice job matching the OPs skill level.
    – MikeyB
    Nov 22 at 1:57















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_())





share|improve this answer





















  • Nice job matching the OPs skill level.
    – MikeyB
    Nov 22 at 1:57













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_())





share|improve this answer












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_())






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 at 7:12









eyllanesc

69k93052




69k93052












  • 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




Nice job matching the OPs skill level.
– MikeyB
Nov 22 at 1:57










ImadX122 is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















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.















 


draft saved


draft discarded














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





















































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







Popular posts from this blog

Berounka

Sphinx de Gizeh

Different font size/position of beamer's navigation symbols template's content depending on regular/plain...