Reputation: 1512
(Python 3.7.3, PyQt5m MacOS Mojave)
In the code that follows I was hoping to see
start_batch
item
item
item
item
returned from start_batch
but what I actually get is
start_batch
returned from start_batch
That is, simulated_item is never running, not even once.
What do I need to do to correct this?
from PyQt5.QtCore import QTimer, QCoreApplication, QThread
import time, sys
class Scanner(object):
def __init__(self):
self.num = -1
def start_batch(self, operator_id, update_callback):
print('start_batch')
self.update_callback = update_callback
QTimer.singleShot(1, self.simulated_item)
def simulated_item(self):
print('item')
self.update_callback()
self.num += 1
if self.num > 4:
self.normal_stop_callback()
return
QTimer.singleShot(100, self.simulated_item)
class dummy(QThread):
def update(self):
print('update')
def run(self):
scnr = Scanner()
scnr.start_batch('opid', self.update)
print('returned from start_batch')
for i in range(10):
time.sleep((0.2))
app = QCoreApplication([])
thread = dummy()
thread.run()
Upvotes: 1
Views: 2134
Reputation: 1512
As discussed in the comment to @eyllansec above, I was able to create a working example which is shown below.
from PyQt5.QtCore import QTimer, QCoreApplication
import sys
class Scanner(object):
def __init__(self, app):
self.num = -1
self.app = app
def simulated_item(self):
self.num += 1
print("item", self.num)
if self.num <= 4:
QTimer.singleShot(500, self.simulated_item)
else:
self.app.exit()
if __name__ == "__main__":
app = QCoreApplication(sys.argv)
scnr = Scanner(app)
scnr.simulated_item()
sys.exit(app.exec_())
Upvotes: 1
Reputation: 243897
In your code you have the error that you are calling the run method directly but that is not appropriate but you have to use the start()
method:
app = QCoreApplication([])
thread = dummy()
thread.start()
app.exec_()
But you still won't get what you want.
Many elements such as the case of QTimer (also the signals) need an event loop to be able to work but when you override the run method that has it by default you have eliminated it so it fails.
So an approximation of what you want may be the following code where the QTimer uses the QCoreApplication event loop:
from PyQt5.QtCore import QTimer, QCoreApplication, QThread
import time, sys
class Scanner(object):
def __init__(self):
self.num = -1
def start_batch(self, operator_id, update_callback):
print("start_batch")
self.update_callback = update_callback
QTimer.singleShot(1, self.simulated_item)
def simulated_item(self):
print("item")
# QTimer.singleShot() is used so that the update_callback function
# is executed in the thread where the QObject to which it belongs lives,
# if it is not a QObject it will be executed in the thread
# where it is invoked
QTimer.singleShot(0, self.update_callback)
# self.update_callback()
self.num += 1
if self.num > 4:
# self.normal_stop_callback()
return
QTimer.singleShot(100, self.simulated_item)
class dummy(QThread):
def update(self):
print("update")
def run(self):
for i in range(10):
time.sleep(0.2)
print("returned from start_batch")
if __name__ == "__main__":
app = QCoreApplication(sys.argv)
thread = dummy()
thread.start()
scnr = Scanner()
thread.started.connect(lambda: scnr.start_batch("opid", thread.update))
sys.exit(app.exec_())
Upvotes: 2