Python Forum
[PyQt] Push Button issue
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] Push Button issue
#1
Please help !
I need help with making my Stopwatch run after click on Button "Start"
===
import sys

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QGridLayout, QSizePolicy, QApplication

global QPushButton

button = QPushButton


class Window(QWidget):
def __init__(self, *args, **kwargs):
self.my_counter = 0 ## replaced "1"
self.my_counter1 = 0
self.my_counter2 = 0
QWidget.__init__(self, *args, **kwargs)

# self.label = QLabel("Q", self) #original
self.label = QLabel(self)
self.label1 = QLabel(self)
self.label2 = QLabel(self)
self.label.setText("00")
self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")


self.label1 = QLabel(self)
self.label1.setAlignment(Qt.AlignCenter)
self.label1.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")
self.label1.setText("00.")

self.label2 = QLabel(self)
self.label2.setAlignment(Qt.AlignCenter)
self.label2.setStyleSheet("QLabel {background-color: pink; font-size: 30pt;}")
self.label2.setText("00:")

self.button = QPushButton(self)
self.button.setStyleSheet("QPushButton {background-color: yellow; font-size: 15pt;}")
self.button.setText("Start")

self.layout = QGridLayout(self)
self.layout.addWidget(self.label, 0, 4)
self.layout.addWidget(self.label1, 0, 3) # New label1
self.layout.addWidget(self.label2, 0, 2) # + New label2
self.layout.addWidget(self.button, 3, 3)

self.setLayout(self.layout)
self.show()

def local_button_handler(self):

self.label.setText("%d" % self.my_counter)
self.my_counter += 1

if self.my_counter == 100:
self.my_counter = 0
self.my_counter1 += 1
self.label1.setText("%d" % self.my_counter1 + ".")

if self.my_counter1 == 60:
self.label1.setText("00.")
self.my_counter1 = 0
self.my_counter2 += 1
self.label2.setText("0"+"%d" % self.my_counter2 + ":")
elif self.my_counter1 < 10:
self.label1.setText("0" + "%d" % self.my_counter1 + ".")

elif self.my_counter < 10:

self.label.setText("0" + "%d" % self.my_counter)

def on_button_clicked(self):

button.clicked.connect(win.local_button_handler())
timer = QTimer()
timer.timeout.connect(win.local_button_handler)
timer.start(10)

on_button_clicked

app = QApplication(sys.argv)
win = Window()
# If to uncomment the code below and to comment the code above
# from line: def on_button_clicked(self):
# through line on_button_clicked
# Stopwatch runs, but I need it to run only after pushbutton has been clicked on
#
# timer = QTimer()
# timer.timeout.connect(win.local_button_handler)
# timer.start(10)
###
app.exec_()
sys.exit(app.exec_())
Reply
#2
You should give you widgets names that indicate what they do like "start_button" or "time_display". You should definitely rename class Window to something like class Stopwatch. Good names go a long way in making programs easy to understand.

After you create the start_button you need to bind it to a function. I'm going to write a new function named "start_timer" (good names make programming easier). start_timer() is going to start the timer. It should reset the tick counter and start the timer. Binding the button to the function is as simple as:
self.start_button.click.connect(self.start_timer)
I start writing the "start_timer()" func. Hey, where is the timer? If you write a stopwatch class it should have a timer somewhere. Add some code to the __init__ method to create a timer (with a good name like "timer") and bind it to the function that updates time. Binding the button click to the start_time function is as simple as:
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_time)
Now I need a "update_time()" function. I see your code has a function named "local_button_handler" that does the counting and updates the time labels. Let's rename that to "update_time". Getting pretty close to making this thing work.

Let's review. Pressing the start_button calls start_timer(). start_timer() starts the timer running. Every ten milliseconds the timer calls update_time(). update_time() increments the tick counters and updates the time labels.

Now all you need is a way to stop the timer.
Reply
#3
Thanks for your advise. Made some changes (see below). Start Button still does not work.
import sys

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QGridLayout, QSizePolicy, QApplication

class Stopwatch(QWidget):

    def __init__(self, *args, **kwargs):

        self.my_counter = 0
        self.my_counter1 = 0
        self.my_counter2 = 0

        QWidget.__init__(self, *args, **kwargs)

        self.label = QLabel(self)
        self.label1 = QLabel(self)
        self.label2 = QLabel(self)
        self.label.setText("00")
        self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")


        self.label1 = QLabel(self)
        self.label1.setAlignment(Qt.AlignCenter)
        self.label1.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")
        self.label1.setText("00.")

        self.label2 = QLabel(self)
        self.label2.setAlignment(Qt.AlignCenter)
        self.label2.setStyleSheet("QLabel {background-color: pink; font-size: 30pt;}")
        self.label2.setText("00:")

        self.start_button = QPushButton(self)
        self.start_button.setStyleSheet("QPushButton {background-color: yellow; font-size: 15pt;}")
        self.start_button.setText("Start")

        self.layout = QGridLayout(self)
        self.layout.addWidget(self.label, 0, 4)
        self.layout.addWidget(self.label1, 0, 3)
        self.layout.addWidget(self.label2, 0, 2)
        self.layout.addWidget(self.start_button, 3, 3)

        self.setLayout(self.layout)
        self.show()

    def update_time(self):

        self.label.setText("%d" % self.my_counter)
        self.my_counter += 1

        if self.my_counter == 100:
            self.my_counter = 0
            self.my_counter1 += 1
            self.label1.setText("%d" % self.my_counter1 + ".")

            if self.my_counter1 == 60:
                self.label1.setText("00.")
                self.my_counter1 = 0
                self.my_counter2 += 1
                self.label2.setText("0"+"%d" % self.my_counter2 + ":")
            elif self.my_counter1  < 10:
                self.label1.setText("0" + "%d" % self.my_counter1 + ".")

        elif self.my_counter < 10:

            self.label.setText("0" +  "%d" % self.my_counter)

    def start_timer(self):

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_time)
        self.timer.start(10)

    def start_button(self):

        self.start_button.click.connect(self.start_timer)


app = QApplication(sys.argv)
win = Stopwatch()
sys.exit(app.exec_())
Reply
#4
Get rid of the start_button method and move that code into the __init__ method. self.timer.start() is the only code that should be in the start_timer method. The self.timer = QTimer() and self.timer.click.connect code should be in the __init__ method
Reply
#5
Thanks again for your help and patience ! Made changes (see code below). Still doesn't work.

import sys

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QGridLayout, QSizePolicy, QApplication

class Stopwatch(QWidget):

    def __init__(self, *args, **kwargs):

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_time)


        def start_button(self):

            self.start_button.click.connect(self.start_timer)


        self.my_counter = 0
        self.my_counter1 = 0
        self.my_counter2 = 0


        QWidget.__init__(self, *args, **kwargs)

        self.label = QLabel(self)
        self.label1 = QLabel(self)
        self.label2 = QLabel(self)
        self.label.setText("00")
        self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")


        self.label1 = QLabel(self)
        self.label1.setAlignment(Qt.AlignCenter)
        self.label1.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")
        self.label1.setText("00.")

        self.label2 = QLabel(self)
        self.label2.setAlignment(Qt.AlignCenter)
        self.label2.setStyleSheet("QLabel {background-color: pink; font-size: 30pt;}")
        self.label2.setText("00:")

        self.start_button = QPushButton(self)
        self.start_button.setStyleSheet("QPushButton {background-color: yellow; font-size: 15pt;}")
        self.start_button.setText("Start")

        self.layout = QGridLayout(self)
        self.layout.addWidget(self.label, 0, 4)
        self.layout.addWidget(self.label1, 0, 3)
        self.layout.addWidget(self.label2, 0, 2)
        self.layout.addWidget(self.start_button, 3, 3)

        self.setLayout(self.layout)
        self.show()
        

    def update_time(self):

        self.label.setText("%d" % self.my_counter)
        self.my_counter += 1

        if self.my_counter == 100:
            self.my_counter = 0
            self.my_counter1 += 1
            self.label1.setText("%d" % self.my_counter1 + ".")

            if self.my_counter1 == 60:
                self.label1.setText("00.")
                self.my_counter1 = 0
                self.my_counter2 += 1
                self.label2.setText("0"+"%d" % self.my_counter2 + ":")
            elif self.my_counter1  < 10:
                self.label1.setText("0" + "%d" % self.my_counter1 + ".")

        elif self.my_counter < 10:

            self.label.setText("0" +  "%d" % self.my_counter)

    def start_timer(self):

        self.timer.start(10)    
 

app = QApplication(sys.argv)
win = Stopwatch()
sys.exit(app.exec_())
Reply
#6
    def __init__(self, *args, **kwargs):
 
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_time)
        …
        self.start_button = QPushButton(self)
        self.start_button.setStyleSheet("QPushButton {background-color: yellow; font-size: 15pt;}")
        self.start_button.setText("Start")
        self.start_button.clicked.connect(self.start_timer)  # Connect button here.  Right after you make it
 
 
        self.my_counter = 0
        self.my_counter1 = 0
        self.my_counter2 = 0
 
 
I have PySide2 instead of Qt5, but they are nearly identical. The signal for the QPushbutton is clicked() instead of click(). Decided to use only one label for the time display 'cause I am lazy.
import sys
from PySide2.QtCore import QTimer
from PySide2.QtWidgets import QWidget, QLabel, QPushButton, QGridLayout, QApplication
 
class Stopwatch(QWidget):
 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
 
        self.tics = 0
        self.increment = 10
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_time)
        
        self.time_display = QLabel(self, text='00:00:00.00')
        self.time_display.setStyleSheet("QLabel {background-color: white; font-size: 50pt;}")
        
        self.start_button = QPushButton(self)
        self.start_button.setStyleSheet("QPushButton {background-color: yellow; font-size: 20pt;}")
        self.start_button.setText("Start")
        self.start_button.clicked.connect(self.start_timer)
        
        self.layout = QGridLayout(self)
        self.layout.addWidget(self.time_display, 0, 0)
        self.layout.addWidget(self.start_button, 1, 0)
          
    def update_time(self):
        """Increment counter and update time display"""
        # Calculate hours:minutes:seconds
        self.tics += self.increment
        h = self.tics // 3600000
        m = (self.tics // 60000) % 60
        s = (self.tics / 1000) % 60
        self.time_display.setText(f'{h:02d}:{m:02d}:{s:05.2f}')
 
    def start_timer(self):
        """Start/Stop the timer"""
        if self.start_button.text() == 'Start':
            self.tics = 0
            self.start_button.setText('Stop')
            self.timer.start(self.increment)
        else:
            self.timer.stop()
            self.start_button.setText('Start')
  
app = QApplication(sys.argv)
win = Stopwatch()
win.setWindowTitle('Stopwatch')
win.show()
sys.exit(app.exec_())
Reply
#7
Thanks again !Doesn't work plus give Error msg
import sys

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QGridLayout, QSizePolicy, QApplication

class Stopwatch(QWidget):

    def __init__(self, QWidget = None, **kwargs):

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_time)

        self.start_button = QPushButton(self, parent = None)
        self.start_button.setStyleSheet("QPushButton {background-color: yellow; font-size: 15pt;}")
        self.start_button.setText("Start")
        self.start_button.click.connect(self.start_timer)  # Connect button here.  Right after you make it

        self.my_counter = 0
        self.my_counter1 = 0
        self.my_counter2 = 0

        QWidget.__init__(self, *args, **kwargs)


        self.label = QLabel(self)
        self.label1 = QLabel(self)
        self.label2 = QLabel(self)
        self.label.setText("00")
        self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")


        self.label1 = QLabel(self)
        self.label1.setAlignment(Qt.AlignCenter)
        self.label1.setStyleSheet("QLabel {background-color: white; font-size: 30pt;}")
        self.label1.setText("00.")

        self.label2 = QLabel(self)
        self.label2.setAlignment(Qt.AlignCenter)
        self.label2.setStyleSheet("QLabel {background-color: pink; font-size: 30pt;}")
        self.label2.setText("00:")

        self.layout = QGridLayout(self)
        self.layout.addWidget(self.label, 0, 4)
        self.layout.addWidget(self.label1, 0, 3)
        self.layout.addWidget(self.label2, 0, 2)
        self.layout.addWidget(self.start_button, 3, 3)

        self.setLayout(self.layout)
        self.show()


    def update_time(self):

        self.label.setText("%d" % self.my_counter)
        self.my_counter += 1

        if self.my_counter == 100:
            self.my_counter = 0
            self.my_counter1 += 1
            self.label1.setText("%d" % self.my_counter1 + ".")

            if self.my_counter1 == 60:
                self.label1.setText("00.")
                self.my_counter1 = 0
                self.my_counter2 += 1
                self.label2.setText("0"+"%d" % self.my_counter2 + ":")
            elif self.my_counter1  < 10:
                self.label1.setText("0" + "%d" % self.my_counter1 + ".")

        elif self.my_counter < 10:

            self.label.setText("0" +  "%d" % self.my_counter)

    def start_timer(self):

        self.timer.start(10)


app = QApplication(sys.argv)
win = Stopwatch()
sys.exit(app.exec_())

# Error msg below
"C:\Program Files\Python36\python.exe" C:/Users/gvin4/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/QTimer1.py
Traceback (most recent call last):
  File "C:/Users/gvin4/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/QTimer1.py", line 82, in <module>
    win = Stopwatch()
  File "C:/Users/gvin4/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/QTimer1.py", line 13, in __init__
    self.start_button = QPushButton(self, parent = None)
RuntimeError: super-class __init__() of type Stopwatch was never called

Process finished with exit code 1
Reply
#8
Dear deanhystad ! Thanks a lot ! Your code is working perfectly well and I've got exactly what I was looking for. I've just changed the library(PyQt5 instead of PySide2). Now I'll try to understand what was wrong in my own code. Thanks again !
Reply
#9
You need to call __init__ for the Stopwatch superclass before you start adding buttons. Calling super().__init__(), super(Stopwatch, this).__init__() or QWidget.__init__(this) teaches class Stopwatch how to do QWidget things. Stopwatch by itself does not know how to be the parent for start_button. That is why you got your error. If you moved the super __init__ to where it belongs (at or near the top of the __init__ method) your program should work.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  tkinter - touchscreen, push the button like click the mouse John64 5 740 Jan-06-2024, 03:45 PM
Last Post: deanhystad
  Centering and adding a push button to a grid window, TKinter Edward_ 15 4,374 May-25-2023, 07:37 PM
Last Post: deanhystad
  [PySimpleGui] How to alter mouse click button of a standard submit button? skyerosebud 3 4,947 Jul-21-2019, 06:02 PM
Last Post: FullOfHelp
  Windows GUI with push buttons to launch python scripts drifterf 7 4,120 Jul-17-2019, 05:34 PM
Last Post: Yoriz
  Text after push button chano 13 5,231 Jul-05-2019, 03:10 PM
Last Post: Yoriz
  [PyQt] Close program using Push Button with the help of input from a Message Box bhargavbn 2 6,607 Oct-30-2018, 05:09 AM
Last Post: bhargavbn
  [Tkinter] Selected radio button in push button in Tkinter prashantfunde91 1 11,766 Jun-22-2017, 05:27 PM
Last Post: DeaD_EyE
  PyQt4 get text from line edit into label on button push iFunKtion 2 21,712 Feb-27-2017, 12:14 PM
Last Post: iFunKtion

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020