Simple PyQt5 counting GUI











up vote
2
down vote

favorite












I just began learning how to use signals and slots in PyQt5, and so I made a cute (pun intended) little program to display just one button. When the button is pressed a thread is spawned which will count from 0 to 99 and display the current count onto the button. However, when the button is counting, the program will not allow the user to spawn another thread.



I am about to actually use my knowledge for a much heavier task, and I wanted to know if there was an easier way to do what I did. Or, perhaps my way is not very efficient? Thanks in advance!



import threading
import sys
import time

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class Application(QMainWindow):
counter = pyqtSignal(str)
counting = False

def __init__(self):
super(Application, self).__init__()

self.button = QPushButton()
self.button.setText('99')
self.button.clicked.connect(self.startCounting)
self.counter.connect(self.button.setText)

self.layout = QVBoxLayout()
self.layout.addWidget(self.button)
self.frame = QFrame()
self.frame.setLayout(self.layout)
self.setCentralWidget(self.frame)

def startCounting(self):
if not self.counting:
self.counting = True
thread = threading.Thread(target=self.something)
thread.start()

def something(self):
for x in range(100):
self.counter.emit(str(x))
time.sleep(.01)
self.counting = False



if __name__ == '__main__':
app = QApplication(sys.argv)
window = Application()
window.show()
sys.exit(app.exec_())









share|improve this question


















  • 1




    I have never used PyQt, so I am asking for my own edification: why do you use a pyqtSignal instead of just setting the text directly?
    – zondo
    Aug 18 '16 at 0:49






  • 1




    @zondo because its 'good practice' to let the main thread handle anything GUI related
    – Nick Pandolfi
    Aug 18 '16 at 1:03















up vote
2
down vote

favorite












I just began learning how to use signals and slots in PyQt5, and so I made a cute (pun intended) little program to display just one button. When the button is pressed a thread is spawned which will count from 0 to 99 and display the current count onto the button. However, when the button is counting, the program will not allow the user to spawn another thread.



I am about to actually use my knowledge for a much heavier task, and I wanted to know if there was an easier way to do what I did. Or, perhaps my way is not very efficient? Thanks in advance!



import threading
import sys
import time

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class Application(QMainWindow):
counter = pyqtSignal(str)
counting = False

def __init__(self):
super(Application, self).__init__()

self.button = QPushButton()
self.button.setText('99')
self.button.clicked.connect(self.startCounting)
self.counter.connect(self.button.setText)

self.layout = QVBoxLayout()
self.layout.addWidget(self.button)
self.frame = QFrame()
self.frame.setLayout(self.layout)
self.setCentralWidget(self.frame)

def startCounting(self):
if not self.counting:
self.counting = True
thread = threading.Thread(target=self.something)
thread.start()

def something(self):
for x in range(100):
self.counter.emit(str(x))
time.sleep(.01)
self.counting = False



if __name__ == '__main__':
app = QApplication(sys.argv)
window = Application()
window.show()
sys.exit(app.exec_())









share|improve this question


















  • 1




    I have never used PyQt, so I am asking for my own edification: why do you use a pyqtSignal instead of just setting the text directly?
    – zondo
    Aug 18 '16 at 0:49






  • 1




    @zondo because its 'good practice' to let the main thread handle anything GUI related
    – Nick Pandolfi
    Aug 18 '16 at 1:03













up vote
2
down vote

favorite









up vote
2
down vote

favorite











I just began learning how to use signals and slots in PyQt5, and so I made a cute (pun intended) little program to display just one button. When the button is pressed a thread is spawned which will count from 0 to 99 and display the current count onto the button. However, when the button is counting, the program will not allow the user to spawn another thread.



I am about to actually use my knowledge for a much heavier task, and I wanted to know if there was an easier way to do what I did. Or, perhaps my way is not very efficient? Thanks in advance!



import threading
import sys
import time

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class Application(QMainWindow):
counter = pyqtSignal(str)
counting = False

def __init__(self):
super(Application, self).__init__()

self.button = QPushButton()
self.button.setText('99')
self.button.clicked.connect(self.startCounting)
self.counter.connect(self.button.setText)

self.layout = QVBoxLayout()
self.layout.addWidget(self.button)
self.frame = QFrame()
self.frame.setLayout(self.layout)
self.setCentralWidget(self.frame)

def startCounting(self):
if not self.counting:
self.counting = True
thread = threading.Thread(target=self.something)
thread.start()

def something(self):
for x in range(100):
self.counter.emit(str(x))
time.sleep(.01)
self.counting = False



if __name__ == '__main__':
app = QApplication(sys.argv)
window = Application()
window.show()
sys.exit(app.exec_())









share|improve this question













I just began learning how to use signals and slots in PyQt5, and so I made a cute (pun intended) little program to display just one button. When the button is pressed a thread is spawned which will count from 0 to 99 and display the current count onto the button. However, when the button is counting, the program will not allow the user to spawn another thread.



I am about to actually use my knowledge for a much heavier task, and I wanted to know if there was an easier way to do what I did. Or, perhaps my way is not very efficient? Thanks in advance!



import threading
import sys
import time

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class Application(QMainWindow):
counter = pyqtSignal(str)
counting = False

def __init__(self):
super(Application, self).__init__()

self.button = QPushButton()
self.button.setText('99')
self.button.clicked.connect(self.startCounting)
self.counter.connect(self.button.setText)

self.layout = QVBoxLayout()
self.layout.addWidget(self.button)
self.frame = QFrame()
self.frame.setLayout(self.layout)
self.setCentralWidget(self.frame)

def startCounting(self):
if not self.counting:
self.counting = True
thread = threading.Thread(target=self.something)
thread.start()

def something(self):
for x in range(100):
self.counter.emit(str(x))
time.sleep(.01)
self.counting = False



if __name__ == '__main__':
app = QApplication(sys.argv)
window = Application()
window.show()
sys.exit(app.exec_())






python gui pyqt






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Aug 17 '16 at 22:01









Nick Pandolfi

274317




274317








  • 1




    I have never used PyQt, so I am asking for my own edification: why do you use a pyqtSignal instead of just setting the text directly?
    – zondo
    Aug 18 '16 at 0:49






  • 1




    @zondo because its 'good practice' to let the main thread handle anything GUI related
    – Nick Pandolfi
    Aug 18 '16 at 1:03














  • 1




    I have never used PyQt, so I am asking for my own edification: why do you use a pyqtSignal instead of just setting the text directly?
    – zondo
    Aug 18 '16 at 0:49






  • 1




    @zondo because its 'good practice' to let the main thread handle anything GUI related
    – Nick Pandolfi
    Aug 18 '16 at 1:03








1




1




I have never used PyQt, so I am asking for my own edification: why do you use a pyqtSignal instead of just setting the text directly?
– zondo
Aug 18 '16 at 0:49




I have never used PyQt, so I am asking for my own edification: why do you use a pyqtSignal instead of just setting the text directly?
– zondo
Aug 18 '16 at 0:49




1




1




@zondo because its 'good practice' to let the main thread handle anything GUI related
– Nick Pandolfi
Aug 18 '16 at 1:03




@zondo because its 'good practice' to let the main thread handle anything GUI related
– Nick Pandolfi
Aug 18 '16 at 1:03










2 Answers
2






active

oldest

votes

















up vote
2
down vote



accepted










Looks good to me!



super minor nits:



        thread = threading.Thread(target=self.something)
thread.start()


only uses the thread variable once, so you might as well do:



        threading.Thread(target=self.something).start()


Also, the only thing you use from threading is Thread so you might as well change your import to:



from threading import Thread


and then it can be just:



Thread(target=self.something).start()


...but again, these are super minor things! It looks good to me; I may have to look at pyQT again :)






share|improve this answer




























    up vote
    1
    down vote













    since you already used signals/slots mechanism in your program you can easily replace python thread mechanism with QThread() and make it use separate Counter() object to divide program into separate logical blocks:



    # Similar to threading.thread(target=self.counter.start)
    self.counterThread = QThread()
    self.counter = Counter()
    self.counter.moveToThread(self.counterThread)
    self.counterThread.started.connect(self.counter.start)


    Where the Counter() class (often named as Worker() class) is:



    class Counter(QObject):
    '''
    Class intended to be used in a separate thread to generate numbers and send
    them to another thread.
    '''

    newValue = pyqtSignal(str)
    stopped = pyqtSignal()

    def __init__(self):
    QObject.__init__(self)

    def start(self):
    '''
    Count from 0 to 99 and emit each value to the GUI thread to display.
    '''

    for x in range(100):
    self.newValue.emit(str(x))
    time.sleep(.01)
    self.stopped.emit()


    By using this approach you can even modify Counter() object to receive some data from the GUI on-the-fly and react accordingly.



    Another minor thing is that "from package import *" was used. Usually it is considered a bad practice since you import all the contents of the package. In this case all QtCore and QtWidgets modules were imported which is ~2/3 of the PyQt5 package itself I believe))) It is more verbose but much better to use:



    from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
    from PyQt5.QtCore import pyqtSignal, QObject, QThread


    or:



    from PyQt5 import QtWidgets, QtCore
    ...
    self.button = QtWidgets.QPushButton()


    That way you and other code readers always know which object belongs to which package as well.



    Here is the complete code rewritten according to those notes:



    '''
    https://codereview.stackexchange.com/questions/138992/simple-pyqt5-counting-gui
    '''

    import sys
    import time

    from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
    from PyQt5.QtCore import pyqtSignal, QObject, QThread

    class Counter(QObject):
    '''
    Class intended to be used in a separate thread to generate numbers and send
    them to another thread.
    '''

    newValue = pyqtSignal(str)
    stopped = pyqtSignal()

    def __init__(self):
    QObject.__init__(self)

    def start(self):
    '''
    Count from 0 to 99 and emit each value to the GUI thread to display.
    '''

    for x in range(100):
    self.newValue.emit(str(x))
    time.sleep(.01)
    self.stopped.emit()


    class Application(QMainWindow):
    def __init__(self):
    QMainWindow.__init__(self)

    # Configuring widgets
    self.button = QPushButton()
    self.button.setText('99')
    self.layout = QVBoxLayout()
    self.layout.addWidget(self.button)
    self.frame = QFrame()
    self.frame.setLayout(self.layout)
    self.setCentralWidget(self.frame)

    # Configuring separate thread
    self.counterThread = QThread()
    self.counter = Counter()
    self.counter.moveToThread(self.counterThread)

    # Connecting signals
    self.button.clicked.connect(self.startCounting)
    self.counter.newValue.connect(self.button.setText)
    self.counter.stopped.connect(self.counterThread.quit)
    self.counterThread.started.connect(self.counter.start)


    def startCounting(self):
    '''
    Start counting if no other counting is done.
    '''

    if not self.counterThread.isRunning():
    self.counterThread.start()


    if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Application()
    window.show()
    sys.exit(app.exec_())


    Keep up the good work and best wishes.






    share|improve this answer





















      Your Answer





      StackExchange.ifUsing("editor", function () {
      return StackExchange.using("mathjaxEditing", function () {
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      });
      });
      }, "mathjax-editing");

      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: "196"
      };
      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: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      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
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f138992%2fsimple-pyqt5-counting-gui%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      2
      down vote



      accepted










      Looks good to me!



      super minor nits:



              thread = threading.Thread(target=self.something)
      thread.start()


      only uses the thread variable once, so you might as well do:



              threading.Thread(target=self.something).start()


      Also, the only thing you use from threading is Thread so you might as well change your import to:



      from threading import Thread


      and then it can be just:



      Thread(target=self.something).start()


      ...but again, these are super minor things! It looks good to me; I may have to look at pyQT again :)






      share|improve this answer

























        up vote
        2
        down vote



        accepted










        Looks good to me!



        super minor nits:



                thread = threading.Thread(target=self.something)
        thread.start()


        only uses the thread variable once, so you might as well do:



                threading.Thread(target=self.something).start()


        Also, the only thing you use from threading is Thread so you might as well change your import to:



        from threading import Thread


        and then it can be just:



        Thread(target=self.something).start()


        ...but again, these are super minor things! It looks good to me; I may have to look at pyQT again :)






        share|improve this answer























          up vote
          2
          down vote



          accepted







          up vote
          2
          down vote



          accepted






          Looks good to me!



          super minor nits:



                  thread = threading.Thread(target=self.something)
          thread.start()


          only uses the thread variable once, so you might as well do:



                  threading.Thread(target=self.something).start()


          Also, the only thing you use from threading is Thread so you might as well change your import to:



          from threading import Thread


          and then it can be just:



          Thread(target=self.something).start()


          ...but again, these are super minor things! It looks good to me; I may have to look at pyQT again :)






          share|improve this answer












          Looks good to me!



          super minor nits:



                  thread = threading.Thread(target=self.something)
          thread.start()


          only uses the thread variable once, so you might as well do:



                  threading.Thread(target=self.something).start()


          Also, the only thing you use from threading is Thread so you might as well change your import to:



          from threading import Thread


          and then it can be just:



          Thread(target=self.something).start()


          ...but again, these are super minor things! It looks good to me; I may have to look at pyQT again :)







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Aug 21 '16 at 6:38









          pjz

          2,061715




          2,061715
























              up vote
              1
              down vote













              since you already used signals/slots mechanism in your program you can easily replace python thread mechanism with QThread() and make it use separate Counter() object to divide program into separate logical blocks:



              # Similar to threading.thread(target=self.counter.start)
              self.counterThread = QThread()
              self.counter = Counter()
              self.counter.moveToThread(self.counterThread)
              self.counterThread.started.connect(self.counter.start)


              Where the Counter() class (often named as Worker() class) is:



              class Counter(QObject):
              '''
              Class intended to be used in a separate thread to generate numbers and send
              them to another thread.
              '''

              newValue = pyqtSignal(str)
              stopped = pyqtSignal()

              def __init__(self):
              QObject.__init__(self)

              def start(self):
              '''
              Count from 0 to 99 and emit each value to the GUI thread to display.
              '''

              for x in range(100):
              self.newValue.emit(str(x))
              time.sleep(.01)
              self.stopped.emit()


              By using this approach you can even modify Counter() object to receive some data from the GUI on-the-fly and react accordingly.



              Another minor thing is that "from package import *" was used. Usually it is considered a bad practice since you import all the contents of the package. In this case all QtCore and QtWidgets modules were imported which is ~2/3 of the PyQt5 package itself I believe))) It is more verbose but much better to use:



              from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
              from PyQt5.QtCore import pyqtSignal, QObject, QThread


              or:



              from PyQt5 import QtWidgets, QtCore
              ...
              self.button = QtWidgets.QPushButton()


              That way you and other code readers always know which object belongs to which package as well.



              Here is the complete code rewritten according to those notes:



              '''
              https://codereview.stackexchange.com/questions/138992/simple-pyqt5-counting-gui
              '''

              import sys
              import time

              from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
              from PyQt5.QtCore import pyqtSignal, QObject, QThread

              class Counter(QObject):
              '''
              Class intended to be used in a separate thread to generate numbers and send
              them to another thread.
              '''

              newValue = pyqtSignal(str)
              stopped = pyqtSignal()

              def __init__(self):
              QObject.__init__(self)

              def start(self):
              '''
              Count from 0 to 99 and emit each value to the GUI thread to display.
              '''

              for x in range(100):
              self.newValue.emit(str(x))
              time.sleep(.01)
              self.stopped.emit()


              class Application(QMainWindow):
              def __init__(self):
              QMainWindow.__init__(self)

              # Configuring widgets
              self.button = QPushButton()
              self.button.setText('99')
              self.layout = QVBoxLayout()
              self.layout.addWidget(self.button)
              self.frame = QFrame()
              self.frame.setLayout(self.layout)
              self.setCentralWidget(self.frame)

              # Configuring separate thread
              self.counterThread = QThread()
              self.counter = Counter()
              self.counter.moveToThread(self.counterThread)

              # Connecting signals
              self.button.clicked.connect(self.startCounting)
              self.counter.newValue.connect(self.button.setText)
              self.counter.stopped.connect(self.counterThread.quit)
              self.counterThread.started.connect(self.counter.start)


              def startCounting(self):
              '''
              Start counting if no other counting is done.
              '''

              if not self.counterThread.isRunning():
              self.counterThread.start()


              if __name__ == '__main__':
              app = QApplication(sys.argv)
              window = Application()
              window.show()
              sys.exit(app.exec_())


              Keep up the good work and best wishes.






              share|improve this answer

























                up vote
                1
                down vote













                since you already used signals/slots mechanism in your program you can easily replace python thread mechanism with QThread() and make it use separate Counter() object to divide program into separate logical blocks:



                # Similar to threading.thread(target=self.counter.start)
                self.counterThread = QThread()
                self.counter = Counter()
                self.counter.moveToThread(self.counterThread)
                self.counterThread.started.connect(self.counter.start)


                Where the Counter() class (often named as Worker() class) is:



                class Counter(QObject):
                '''
                Class intended to be used in a separate thread to generate numbers and send
                them to another thread.
                '''

                newValue = pyqtSignal(str)
                stopped = pyqtSignal()

                def __init__(self):
                QObject.__init__(self)

                def start(self):
                '''
                Count from 0 to 99 and emit each value to the GUI thread to display.
                '''

                for x in range(100):
                self.newValue.emit(str(x))
                time.sleep(.01)
                self.stopped.emit()


                By using this approach you can even modify Counter() object to receive some data from the GUI on-the-fly and react accordingly.



                Another minor thing is that "from package import *" was used. Usually it is considered a bad practice since you import all the contents of the package. In this case all QtCore and QtWidgets modules were imported which is ~2/3 of the PyQt5 package itself I believe))) It is more verbose but much better to use:



                from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
                from PyQt5.QtCore import pyqtSignal, QObject, QThread


                or:



                from PyQt5 import QtWidgets, QtCore
                ...
                self.button = QtWidgets.QPushButton()


                That way you and other code readers always know which object belongs to which package as well.



                Here is the complete code rewritten according to those notes:



                '''
                https://codereview.stackexchange.com/questions/138992/simple-pyqt5-counting-gui
                '''

                import sys
                import time

                from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
                from PyQt5.QtCore import pyqtSignal, QObject, QThread

                class Counter(QObject):
                '''
                Class intended to be used in a separate thread to generate numbers and send
                them to another thread.
                '''

                newValue = pyqtSignal(str)
                stopped = pyqtSignal()

                def __init__(self):
                QObject.__init__(self)

                def start(self):
                '''
                Count from 0 to 99 and emit each value to the GUI thread to display.
                '''

                for x in range(100):
                self.newValue.emit(str(x))
                time.sleep(.01)
                self.stopped.emit()


                class Application(QMainWindow):
                def __init__(self):
                QMainWindow.__init__(self)

                # Configuring widgets
                self.button = QPushButton()
                self.button.setText('99')
                self.layout = QVBoxLayout()
                self.layout.addWidget(self.button)
                self.frame = QFrame()
                self.frame.setLayout(self.layout)
                self.setCentralWidget(self.frame)

                # Configuring separate thread
                self.counterThread = QThread()
                self.counter = Counter()
                self.counter.moveToThread(self.counterThread)

                # Connecting signals
                self.button.clicked.connect(self.startCounting)
                self.counter.newValue.connect(self.button.setText)
                self.counter.stopped.connect(self.counterThread.quit)
                self.counterThread.started.connect(self.counter.start)


                def startCounting(self):
                '''
                Start counting if no other counting is done.
                '''

                if not self.counterThread.isRunning():
                self.counterThread.start()


                if __name__ == '__main__':
                app = QApplication(sys.argv)
                window = Application()
                window.show()
                sys.exit(app.exec_())


                Keep up the good work and best wishes.






                share|improve this answer























                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  since you already used signals/slots mechanism in your program you can easily replace python thread mechanism with QThread() and make it use separate Counter() object to divide program into separate logical blocks:



                  # Similar to threading.thread(target=self.counter.start)
                  self.counterThread = QThread()
                  self.counter = Counter()
                  self.counter.moveToThread(self.counterThread)
                  self.counterThread.started.connect(self.counter.start)


                  Where the Counter() class (often named as Worker() class) is:



                  class Counter(QObject):
                  '''
                  Class intended to be used in a separate thread to generate numbers and send
                  them to another thread.
                  '''

                  newValue = pyqtSignal(str)
                  stopped = pyqtSignal()

                  def __init__(self):
                  QObject.__init__(self)

                  def start(self):
                  '''
                  Count from 0 to 99 and emit each value to the GUI thread to display.
                  '''

                  for x in range(100):
                  self.newValue.emit(str(x))
                  time.sleep(.01)
                  self.stopped.emit()


                  By using this approach you can even modify Counter() object to receive some data from the GUI on-the-fly and react accordingly.



                  Another minor thing is that "from package import *" was used. Usually it is considered a bad practice since you import all the contents of the package. In this case all QtCore and QtWidgets modules were imported which is ~2/3 of the PyQt5 package itself I believe))) It is more verbose but much better to use:



                  from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
                  from PyQt5.QtCore import pyqtSignal, QObject, QThread


                  or:



                  from PyQt5 import QtWidgets, QtCore
                  ...
                  self.button = QtWidgets.QPushButton()


                  That way you and other code readers always know which object belongs to which package as well.



                  Here is the complete code rewritten according to those notes:



                  '''
                  https://codereview.stackexchange.com/questions/138992/simple-pyqt5-counting-gui
                  '''

                  import sys
                  import time

                  from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
                  from PyQt5.QtCore import pyqtSignal, QObject, QThread

                  class Counter(QObject):
                  '''
                  Class intended to be used in a separate thread to generate numbers and send
                  them to another thread.
                  '''

                  newValue = pyqtSignal(str)
                  stopped = pyqtSignal()

                  def __init__(self):
                  QObject.__init__(self)

                  def start(self):
                  '''
                  Count from 0 to 99 and emit each value to the GUI thread to display.
                  '''

                  for x in range(100):
                  self.newValue.emit(str(x))
                  time.sleep(.01)
                  self.stopped.emit()


                  class Application(QMainWindow):
                  def __init__(self):
                  QMainWindow.__init__(self)

                  # Configuring widgets
                  self.button = QPushButton()
                  self.button.setText('99')
                  self.layout = QVBoxLayout()
                  self.layout.addWidget(self.button)
                  self.frame = QFrame()
                  self.frame.setLayout(self.layout)
                  self.setCentralWidget(self.frame)

                  # Configuring separate thread
                  self.counterThread = QThread()
                  self.counter = Counter()
                  self.counter.moveToThread(self.counterThread)

                  # Connecting signals
                  self.button.clicked.connect(self.startCounting)
                  self.counter.newValue.connect(self.button.setText)
                  self.counter.stopped.connect(self.counterThread.quit)
                  self.counterThread.started.connect(self.counter.start)


                  def startCounting(self):
                  '''
                  Start counting if no other counting is done.
                  '''

                  if not self.counterThread.isRunning():
                  self.counterThread.start()


                  if __name__ == '__main__':
                  app = QApplication(sys.argv)
                  window = Application()
                  window.show()
                  sys.exit(app.exec_())


                  Keep up the good work and best wishes.






                  share|improve this answer












                  since you already used signals/slots mechanism in your program you can easily replace python thread mechanism with QThread() and make it use separate Counter() object to divide program into separate logical blocks:



                  # Similar to threading.thread(target=self.counter.start)
                  self.counterThread = QThread()
                  self.counter = Counter()
                  self.counter.moveToThread(self.counterThread)
                  self.counterThread.started.connect(self.counter.start)


                  Where the Counter() class (often named as Worker() class) is:



                  class Counter(QObject):
                  '''
                  Class intended to be used in a separate thread to generate numbers and send
                  them to another thread.
                  '''

                  newValue = pyqtSignal(str)
                  stopped = pyqtSignal()

                  def __init__(self):
                  QObject.__init__(self)

                  def start(self):
                  '''
                  Count from 0 to 99 and emit each value to the GUI thread to display.
                  '''

                  for x in range(100):
                  self.newValue.emit(str(x))
                  time.sleep(.01)
                  self.stopped.emit()


                  By using this approach you can even modify Counter() object to receive some data from the GUI on-the-fly and react accordingly.



                  Another minor thing is that "from package import *" was used. Usually it is considered a bad practice since you import all the contents of the package. In this case all QtCore and QtWidgets modules were imported which is ~2/3 of the PyQt5 package itself I believe))) It is more verbose but much better to use:



                  from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
                  from PyQt5.QtCore import pyqtSignal, QObject, QThread


                  or:



                  from PyQt5 import QtWidgets, QtCore
                  ...
                  self.button = QtWidgets.QPushButton()


                  That way you and other code readers always know which object belongs to which package as well.



                  Here is the complete code rewritten according to those notes:



                  '''
                  https://codereview.stackexchange.com/questions/138992/simple-pyqt5-counting-gui
                  '''

                  import sys
                  import time

                  from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
                  from PyQt5.QtCore import pyqtSignal, QObject, QThread

                  class Counter(QObject):
                  '''
                  Class intended to be used in a separate thread to generate numbers and send
                  them to another thread.
                  '''

                  newValue = pyqtSignal(str)
                  stopped = pyqtSignal()

                  def __init__(self):
                  QObject.__init__(self)

                  def start(self):
                  '''
                  Count from 0 to 99 and emit each value to the GUI thread to display.
                  '''

                  for x in range(100):
                  self.newValue.emit(str(x))
                  time.sleep(.01)
                  self.stopped.emit()


                  class Application(QMainWindow):
                  def __init__(self):
                  QMainWindow.__init__(self)

                  # Configuring widgets
                  self.button = QPushButton()
                  self.button.setText('99')
                  self.layout = QVBoxLayout()
                  self.layout.addWidget(self.button)
                  self.frame = QFrame()
                  self.frame.setLayout(self.layout)
                  self.setCentralWidget(self.frame)

                  # Configuring separate thread
                  self.counterThread = QThread()
                  self.counter = Counter()
                  self.counter.moveToThread(self.counterThread)

                  # Connecting signals
                  self.button.clicked.connect(self.startCounting)
                  self.counter.newValue.connect(self.button.setText)
                  self.counter.stopped.connect(self.counterThread.quit)
                  self.counterThread.started.connect(self.counter.start)


                  def startCounting(self):
                  '''
                  Start counting if no other counting is done.
                  '''

                  if not self.counterThread.isRunning():
                  self.counterThread.start()


                  if __name__ == '__main__':
                  app = QApplication(sys.argv)
                  window = Application()
                  window.show()
                  sys.exit(app.exec_())


                  Keep up the good work and best wishes.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 2 days ago









                  Vasyalisk

                  35129




                  35129






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Code Review Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      Use MathJax to format equations. MathJax reference.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f138992%2fsimple-pyqt5-counting-gui%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

                      Mont Emei

                      Province de Neuquén

                      Journaliste