Program has to wait till two threads (Sql query execution) are completed - python

I have a program which compares to DB table values and i have created a GUI in PyQt5. I have created two threads one for querying each table and then program has to wait till two threads are completed. My code below
from PySide2 import QtWidgets
from PySide2 import QtGui
from PySide2 import QtCore
from Main_interface import Ui_mainWindow
import pandas as pd
class mainWindow(QtWidgets.QMainWindow, Ui_mainWindow):
sqlClicked1 = QtCore.Signal(str)
sqlClicked2 = QtCore.Signal(str)
def __init__(self, parent=None):
super(mainWindow, self).__init__(parent)
self.setupUi(self)
self.thread = QtCore.QThread(self)
self.thread.start()
self.obj = Worker()
self.obj.moveToThread(self.thread)
self.sqlClicked.connect(self.obj.runsql_MC)
self.sqlClicked1.connect(self.obj.runsql_IRI)
self.obj.error.connect(self.on_error)
def run_report(self):
sqlquery1 = "Select * from table1"
sqlquery2 = "Select * from table2"
df1 = self.sqlClicked1.emit(sqlquery1)
df2 = self.sqlClicked2.emit(sqlquery2)
self.sqlClicked1.finished.connect(self.on_finished)
self.sqlClicked2.finished.connect(self.on_finished)
print("SQL execution is done")
#Then i am calling function to compare two dataframes
class Worker(QtCore.QObject):
finished = QtCore.Signal()
result = QtCore.Signal(object)
#QtCore.Slot(str)
def runsql_MC(self, sqlquery_MC):
print("Thread1 is working")
try:
df1 = pd.read_sql(sql=sqlquery_MC, con=cnxn)
except:
traceback.print_exc()
else:
self.signals.result.emit(df1) # Return the result of the processing
finally:
self.signals.finished.emit() # Done
#QtCore.Slot(str)
def runsql_IRI(self, sqlquery_IRI):
print("Thread2 is working")
try:
df2 = pd.read_sql(sql=sqlquery_IRI, con=cnxn)
except:
traceback.print_exc()
else:
self.signals.result.emit(df2)
finally:
self.signals.finished.emit()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
my_app = mainWindow()
my_app.show()
sys.exit(app.exec_())
self.sqlClicked1.emit(sqlquery1) and self.sqlClicked2.emit(sqlquery2) is calling corresponding threads runsql_MC() and runsql_IRI. Then I need to wait till two threads are completed to start comparison process. Currently its not happening.

Although your code is not an MRE, show your ignorance of various concepts.
The emission of a signal does not imply obtaining the data as a result since it will be sent asynchronously.
In your code even if you invoke 2 queries does not imply that each one runs on different threads since the worker lives in a single thread.
Your runsql_MC and runsql_IRI methods are redundant since they are a template of the same thing.
In addition to other errors such as that there is no object/signal called sqlClicked, you have not declared the object signals, etc.
The idea is to have a worker who lives in a different thread for each query, and create a class that handles the workers waiting for the data and eliminating when they have finished their work.
from functools import partial
import sqlite3
import pandas as pd
from PySide2 import QtCore, QtGui, QtWidgets
class Worker(QtCore.QObject):
finished = QtCore.Signal()
result = QtCore.Signal(object)
#QtCore.Slot(str)
def runsql(self, query):
cnxn = sqlite3.connect("test.db")
print("Thread1 is working")
try:
df1 = pd.read_sql(sql=query, con=cnxn)
except:
traceback.print_exc()
else:
self.result.emit(df1) # Return the result of the processing
finally:
self.finished.emit() # Done
class SqlManager(QtCore.QObject):
results = QtCore.Signal(list)
def __init__(self, parent=None):
super().__init__(parent)
self.workers_and_threads = {}
self.dataframes = []
def execute_queries(self, queries):
for query in queries:
thread = QtCore.QThread(self)
thread.start()
worker = Worker()
worker.result.connect(self.onResults)
worker.moveToThread(thread)
self.workers_and_threads[worker] = thread
# launch task
wrapper = partial(worker.runsql, query)
QtCore.QTimer.singleShot(0, wrapper)
#QtCore.Slot(object)
def onResults(self, result):
worker = self.sender()
thread = self.workers_and_threads[worker]
thread.quit()
thread.wait()
del self.workers_and_threads[worker]
worker.deleteLater()
self.dataframes.append(result)
if not self.workers_and_threads:
self.results.emit(self.dataframes)
self.dataframes = []
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.push_button = QtWidgets.QPushButton("Run Report")
self.push_button.clicked.connect(self.run_report)
self.setCentralWidget(self.push_button)
self.manager = SqlManager(self)
self.manager.results.connect(self.onResults)
#QtCore.Slot()
def run_report(self):
sqlquery1 = "Select * from table1"
sqlquery2 = "Select * from table2"
queries = [sqlquery1, sqlquery2]
self.manager.execute_queries(queries)
self.push_button.setEnabled(False)
#QtCore.Slot(list)
def onResults(self, dataframes):
print(dataframes)
self.push_button.setEnabled(True)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
my_app = MainWindow()
my_app.show()
sys.exit(app.exec_())

I'm not quite sure if it is written in your code but Have you ever uses a join() sentence to wait till those threads end? You should be using it when you awake those two threads inside your def __init__() method from your mainWindow class

Related

Consolidating slots in PyQt5

How can I reduce the number of pyqtSlot() functions so that I don't need to have two of each? It seems like there should be a better way of doing this, but I haven't been able to figure it out.
The code takes two files, reads each file on different threads, and prints the outputs to different QPlainTextEdit objects.
import sys
import time
import traceback
import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from compare_files_gui import Ui_MainWindow
class WorkerSignals(QObject):
"""Defines signals from running worker thread."""
finished = pyqtSignal()
error = pyqtSignal(tuple)
result = pyqtSignal(str)
progress = pyqtSignal(str)
bar = pyqtSignal(int)
class Worker(QRunnable):
"""Worker thread."""
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
self.kwargs['progress_callback'] = self.signals.progress
self.kwargs['pbar'] = self.signals.bar
#pyqtSlot()
def run(self):
try:
result = self.fn(*self.args, **self.kwargs)
except:
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else:
self.signals.result.emit(result)
finally:
self.signals.finished.emit()
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.compare)
self.ui.file1_progressBar.setValue(0)
self.ui.file2_progressBar.setValue(0)
self.ui.file1_lineEdit.setText('file1.csv')
self.ui.file2_lineEdit.setText('file2.csv')
self.file1 = self.ui.file1_lineEdit.text()
self.file2 = self.ui.file2_lineEdit.text()
self.threadpool = QThreadPool()
##### How can I consolidate the following slots so I don't need to
##### have 2, one for each console object?
#pyqtSlot(str)
def progress_fn1(self, n):
self.ui.console1_plainTextEdit.appendPlainText(n)
#pyqtSlot(str)
def progress_fn2(self, n):
self.ui.console2_plainTextEdit.appendPlainText(n)
#pyqtSlot(str)
def print_output1(self, s):
self.ui.console1_plainTextEdit.appendPlainText(s)
#pyqtSlot(str)
def print_output2(self, s):
self.ui.console2_plainTextEdit.appendPlainText(s)
#pyqtSlot()
def thread_complete1(self):
self.ui.console1_plainTextEdit.appendPlainText('Processing complete!')
#pyqtSlot()
def thread_complete2(self):
self.ui.console2_plainTextEdit.appendPlainText('Processing complete!')
#pyqtSlot(int)
def update_progress1(self, v):
self.ui.file1_progressBar.setValue(v)
#pyqtSlot(int)
def update_progress2(self, v):
self.ui.file2_progressBar.setValue(v)
def compare(self):
# files = [self.ui.file1_lineEdit.text(), self.ui.file2_lineEdit.text()]
files = [self.file1, self.file2]
# Start new thread for each file
for i, file in enumerate(files, 1):
worker = Worker(self.process_file, file)
#### Is there a better way to do this?
if i == 1:
worker.signals.progress.connect(self.progress_fn1)
worker.signals.result.connect(self.print_output1)
worker.signals.finished.connect(self.thread_complete1)
worker.signals.bar.connect(self.update_progress1)
elif i == 2:
worker.signals.progress.connect(self.progress_fn2)
worker.signals.result.connect(self.print_output2)
worker.signals.finished.connect(self.thread_complete2)
worker.signals.bar.connect(self.update_progress2)
else:
pass
# Execute thread
self.threadpool.start(worker)
def process_file(self, file, pbar, progress_callback):
"""Process file and emit signals."""
t0 = time.time()
progress_callback.emit(f'Processing {file}')
df = pd.read_csv(file, header=None, names=['col'])
num = len(df.index)
for i, (index, row) in enumerate(df.iterrows(), 1):
progress_callback.emit(' ' + row['col'])
pbar.emit(int(i*100/num))
time.sleep(0.25)
t1 = time.time()
return f'Time to complete: {round(t1-t0, 3)} s'
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
To fix the issue, I passed on the QPlainTextEdit and QProgressBar objects associated with each file to the thread, and then emitted those from the thread, so that I could determine which QPlainTextEdit to print to. From what I've read online, I don't think passing UI objects to background threads is a best practice, but it works for this simple application and I haven't been able to figure out a better way to do it.
import sys
import time
import traceback
import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from compare_files_gui import Ui_MainWindow
class WorkerSignals(QObject):
"""Defines signals from running worker thread."""
finished = pyqtSignal(object)
error = pyqtSignal(tuple)
result = pyqtSignal(object, str)
progress = pyqtSignal(object, str)
bar = pyqtSignal(object, int)
class Worker(QRunnable):
"""Worker thread."""
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
# Store constructor arguments
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
# Add callbacks to kwargs
self.kwargs['progress_callback'] = self.signals.progress
self.kwargs['pbar_callback'] = self.signals.bar
#pyqtSlot()
def run(self):
try:
console, result = self.fn(*self.args, **self.kwargs)
except:
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else:
self.signals.result.emit(console, result)
finally:
self.signals.finished.emit(console)
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# Initialize progress bars
self.ui.file1_progressBar.setValue(0)
self.ui.file2_progressBar.setValue(0)
# Connect widgets to slots
self.ui.pushButton.clicked.connect(self.compare)
# Create instance of QThreadPool
self.threadpool = QThreadPool()
#pyqtSlot(object, str)
def progress_fn(self, console, n):
"""Print progress string to specific QPlainTextEdit object."""
console.appendPlainText(n)
#pyqtSlot(object, str)
def print_output(self, console, s):
"""Print result string to specific QPlainTextEdit object."""
console.appendPlainText(s)
#pyqtSlot(object)
def thread_complete(self, console):
"""Print completion text to specific QPlainTextEdit object."""
console.appendPlainText('Processing complete!')
#pyqtSlot(object, int)
def update_progress(self, pbar, v):
"""Set value of QProgressBar object."""
pbar.setValue(v)
def compare(self):
"""Send each file and associated UI objects to thread."""
# Store files in list
# files = [self.ui.file1_lineEdit.text(), self.ui.file2_lineEdit.text()]
files = [self.file1, self.file2]
# Store QPlainTextEdit and QProgressBar objects in list
consoles = [self.ui.console1_plainTextEdit, self.ui.console2_plainTextEdit]
pbars = [self.ui.file1_progressBar, self.ui.file2_progressBar]
# Start new thread for each file
for i, (file, console, pbar) in enumerate(zip(files, consoles, pbars), 1):
worker = Worker(self.process_file, file, console, pbar)
# Connect thread signals to slots in UI thread
worker.signals.progress.connect(self.progress_fn)
worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete)
worker.signals.bar.connect(self.update_progress)
# Execute thread
self.threadpool.start(worker)
def process_file(self, file, console, pbar, pbar_callback, progress_callback):
"""Process file and emit signals."""
t0 = time.time()
progress_callback.emit(console, f'Processing {file}')
# Read file into dataframe
df = pd.read_csv(file, header=None, names=['col'])
# Iterate over each row and emit value of column and progress
num = len(df.index)
for i, (index, row) in enumerate(df.iterrows(), 1):
progress_callback.emit(console, ' ' + row['col'])
pbar_callback.emit(pbar, int(i*100/num))
# Slow down response
time.sleep(0.25)
t1 = time.time()
# Return QPlainTextEdit object and string
return console, f'Time to complete: {round(t1-t0, 3)} s'
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())

PyQt5 run same thread dynamically

I am useing python 3.7 and pyqt5
What I want to do is run same QObject with different thread many times.
here is my main
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import threading
import sys
from Worker_Starting import Worker_Starting
class Main(QMainWindow):
def __init__(self) :
super().__init__()
self.setupUI()
self.initSignal()
def setupUI(self):
self.resize(400, 400)
self.pushButton = QPushButton("Start", self)
self.pushButton_2 = QPushButton("Stop", self)
self.pushButton.move(0,0)
self.pushButton_2.move(120,0)
def initSignal(self) :
self.pushButton.clicked.connect(self.Start)
self.pushButton_2.clicked.connect(self.Stop)
#pyqtSlot()
def Start(self) :
for i in range(3) :
print('main', threading.get_ident())
input = ["userID", "userNAME"]
self.my_thread = QThread()
self.my_worker = Worker_Starting(passing_list=input)
self.my_worker.moveToThread(self.my_thread)
self.my_thread.started.connect(self.my_worker.my_fn)
self.my_thread.start()
time.sleep(3)
#pyqtSlot()
def Stop(self) :
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Main()
window.show()
app.exec_()
and my Qobject
from PyQt5 import QtCore
from PyQt5.QtCore import *
import time
import threading
class Worker_Starting(QObject):
def __init__(self, passing_list, parent=None):
QtCore.QThread.__init__(self, parent=parent)
self.userid = passing_list[0]
self.username = passing_list[1]
def my_fn(self):
print(self.username, threading.get_ident())
for i in range(10) :
Now = time.strftime("%Y/%m/%d %H:%M:%S")
print(str(i) + " : " + self.username + " running" + " : " + Now)
time.sleep(0.5)
I put for i in range(3): under def start(self):
because in my actual main script other thread emit input to def start(self): several times.
if I emit only one time, def start(self): works fine.
but when I emit several times, it chrashs.
since I have to emit several times and I need my_thread to work simultaneously and continuously
is there anyway to set same Qobject to different thread?
and how to know or set thread id.
and how to stop thread by thread id.
*I have tried QRunnable, I now it works multi thread. but I have to emit signal back continouously to my main. as far as I know QRunnable are not suitable for custom signal.
The problem is that you're constantly creating new threads by overwriting the existing one, which results in the previous being garbage collected before it's completed, hence the crash.
If you want to execute the same "worker" function concurrently, you cannot use a single object for more threads, as you should use moveToThread each time and this is not possible.
The solution is to use QRunnable instead, implement the function within its run() method, and call QThreadPool to run it.
class Worker_Starting(QRunnable):
def __init__(self, passing_list):
QRunnable.__init__(self)
self.setAutoDelete(False)
self.userid = passing_list[0]
self.username = passing_list[1]
def run(self):
print(self.username, threading.get_ident())
for i in range(10) :
Now = time.strftime("%Y/%m/%d %H:%M:%S")
print(str(i) + " : " + self.username + " running" + " : " + Now)
time.sleep(0.5)
class Main(QMainWindow):
def __init__(self) :
super().__init__()
self.setupUI()
self.initSignal()
self.worker = None
# ...
def Start(self) :
if not self.worker:
input = ["userID", "userNAME"]
self.worker = Worker_Starting(passing_list=input)
for i in range(3):
print('main', threading.get_ident())
QThreadPool.globalInstance().start(self.worker)
Remember that you should not use blocking functions within the main Qt thread (that's why I removed time.sleep(3) from Start()). If you want to start the function more than once at regular intervals, use a QTimer:
interval = 3000 # interval is in milliseconds
for i in range(3):
print('main', threading.get_ident())
QTimer.singleShot(interval * i, lambda:
QThreadPool.globalInstance().start(self.worker))
Note that the pyqtSlot() decorator is usually needed only for special cases and advanced implementation, so you should remove it. Also note that only classes and constants should have capitalized names, while functions, variables and attributes should be lower cased (prefer start and stop instead of Start and Stop).

How can I use a QDateTime inside a Thread?

I have a thread where I need to execute a heavy function.
First, I have a function that takes two QDateTime values from the GUI and convert them to UNIX timestamps. Secondly, the "heavy" function uses these values to perform a task.
Both functions (function_task, time_converter_to_unix) do not belong to any class, so as far as I know I can use them in the thread.
But not the parameters, since I cannot access the QDateTime values.
Error: AttributeError: 'TaskThread' object has no attribute 'startTime'
How can I access the QDateTime and read the content from the thread? Thank you.
EDIT: Complete Code. You can find also the link to the GUI in the following link: interface.ui
import sys
import datetime
import time
from PyQt4 import QtCore, QtGui, uic
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# Link to GUI
qtCreatorFile = "interface.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
def time_converter_to_unix(start_datetime, end_datetime):
# Convert QTimeEdit to UNIX Timestamp (int, msec included), and then to float
start_datetime_unix_int = start_datetime.toMSecsSinceEpoch ()
start_datetime_unix = (float(start_datetime_unix_int) / 1000)
end_datetime_unix_int = end_datetime.toMSecsSinceEpoch ()
end_datetime_unix = (float(end_datetime_unix_int) / 1000)
return start_datetime_unix, end_datetime_unix
def dummy_function(self, start_datetime_unix, end_datetime_unix):
# Dummy function, just to simulate a task
result = start_datetime_unix + end_datetime_unix
print result
class Tool(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent = None):
# Setting-ip UI
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
# Button Action
self.runButton.clicked.connect(self.onStart)
# Progress Bar and Label. At the begining, the bar is at 0
self.progressBar.setValue(0)
self.progressBar.setRange(0,100)
self.resultLabel.setText("Waiting...")
#Thread
self.myLongTask = TaskThread()
self.myLongTask.taskFinished.connect(self.onFinished)
def onStart(self):
# Before running the thread, we set the progress bar in waiting mode
self.progressBar.setRange(0,0)
self.resultLabel.setText("In progress...")
print "Starting thread..."
self.myLongTask.start()
def onFinished(self):
# Stop the pulsation when the thread has finished
self.progressBar.setRange(0,1)
self.progressBar.setValue(1)
self.resultLabel.setText("Done")
class TaskThread(QtCore.QThread):
taskFinished = QtCore.pyqtSignal()
def __init__(self):
QtCore.QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
# First, we read the times from the QDateTime elements in the interface
print "Getting times..."
start_datetime_unix, end_datetime_unix = time_converter_to_unix(self.startTime.dateTime(), self.endTime.dateTime())
# Then, we put these values in my_function
print "Executing function..."
dummy_function(self, start_datetime_unix, end_datetime_unix)
# To finish, we execute onFinished.
print "Finishing thread..."
self.taskFinished.emit()
def main():
app = QtGui.QApplication(sys.argv)
window = Tool()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If you execute it along with the .ui, you will see, that once we click on "Run", the Progress bar stays in waiting mode, and the error commented above appears.
startTime and endTime belong to the GUI, and not to the thread, that's why you get that error.
On the other hand it is advisable not to access the GUI from the other thread, it is best to obtain the values ​​before starting the thread and set it as property of the thread as shown below:
class Tool(QtGui.QMainWindow, Ui_MainWindow):
...
def onStart(self):
# Before running the thread, we set the progress bar in waiting mode
self.progressBar.setRange(0,0)
self.resultLabel.setText("In progress...")
self.myLongTask.start_dt = self.startTime.dateTime() # <----
self.myLongTask.end_dt = self.endTime.dateTime() # <----
print "Starting thread..."
self.myLongTask.start()
...
class TaskThread(QtCore.QThread):
...
def run(self):
# First, we read the times from the QDateTime elements in the interface
print "Getting times..."
start_datetime_unix, end_datetime_unix = time_converter_to_unix(self.start_dt, self.end_dt) # <----
# Then, we put these values in my_function
print "Executing function..."
dummy_function(self, start_datetime_unix, end_datetime_unix)
# To finish, we execute onFinished.
print "Finishing thread..."
self.taskFinished.emit()

Misbehaving QSignals in QThreadPool, QRunnable using QThead on top of it in python

Im stuck in one situation where my first few signals are getting passed and later on no signals are getting emitted.
I'll elaborate it in detail:
I've a job which required heavy processing and ram and can take upto 2-4 hours to complete it without threading in linear way, so I decided to use QTheadPool, so I created (while testing) 355 QRunners which gets started by QThreadPool. And few of them(QRunners) are depends on another QRunners to finish. Its all working fine, I'm able to derive dependencies by emitting signals and catching them. Its all working absolutely perfect when I run this without GUI
For example (below codes are not tested, i just typed here):
from PyQt4 import QtCore
class StreamPool(QtCore.QObject):
def __init__(self, inputs, q_app):
super(....)
self.inputs = inputs
self.q_app = q_app
self.pool = QtCore.QThreadPool()
def start(self):
for each_input in self.inputs:
runner = StreamRunner(each_input, self.q_app)
runner.signal.operation_started.connect(self.mark_as_start)
runner.signal.operation_finished.connect(self.mark_as_start)
self.pool.start(runner)
def mark_as_start(self, name):
print 'operation started..', name
# Some operation...
def mark_as_finish(self, name):
print 'operation finished..', name
# Some operation...
class StreamRunner(QtCore.QRunnable):
def __init__(self, input, q_app):
super(..)
self.input = input
self.q_app = q_app
self.signal = WorkSignals()
def run(self):
self.signal.operation_started.emit(input)
self.q_ap
# Doing some operations
self.signal.operation_finished.emit(input)
self.q_app.processEvents()
class WorkSignals(QtCore.QObject):
operation_started = QtCore.pyqtSignal(str)
operation_finished= QtCore.pyqtSignal(str)
if __name__ == '__main__':
app = QtGui.QApplication([])
st = StreamPool(['a', 'b', 'c'], app)
st.start()
app.exec_()
It works brilliant in above case.
And I want to show the statuses in ui as there can be hundreds of task can be executed, so I wrote a simple ui, and running StreamPool() from another QThread lets say named - StreamWorkThread() which is getting spawned by ui, and StreamWorkThread catching StreamPool.signal.* and sending them back to ui, but in this case StreamPool can only emit few of them, the starting 4 or 5, though the tasks are still getting executed but the dependent task are not getting initialized due to this behavior and no status updates are getting displayed in ui.
I cant share the code with you guys, as its from my work place, I can write similar approach here
class StreamWorkThread (QtCore.QThread):
def __init__(self, inputs, q_app):
super(..)
self.signal = WorkSignals()
self.stream_pool = StreamPool(inputs, q_app)self.stream_pool.signal.operation_started.connect(self.signal.operation_started.emit)
self.stream_pool.signal.operation_finished.connect(self.signal.operation_finished.emit)
def run(self):
self.stream_pool.start()
def print_start(name):
print 'Started --', name
def print_finished(name):
print 'Finished --', name
if __name__ == '__main__':
app = QtGui.QApplication([])
th = StreamWorkThread (['a', 'b', 'c'], app)
th.signal.operation_started.connect(print_start)
th.signal.operation_finshed.connect(print_finished)
th.start()
app.exec_()
Consolidated code:
from PyQt4 import QtCore
class StreamPool(QtCore.QObject):
def __inti__(self, inputs, q_app):
super(StreamPool, self).__init()
self.inputs = inputs
self.q_app = q_app
self.pool = QtCore.QThreadPool()
def start(self):
for each_input in self.inputs:
runner = StreamRunner(each_input, self.q_app)
runner.signal.operation_started.connect(self.mark_as_start)
runner.signal.operation_finished.connect(self.mark_as_start)
self.pool.start(runner)
def mark_as_start(self, name):
print 'operation started..', name
# Some operation...
def mark_as_finish(self, name):
print 'operation finished..', name
# Some operation...
class StreamRunner(QtCore.QRunnable):
def __init__(self, input, q_app):
super(StreamRunner, self).__init()
self.input = input
self.q_app = q_app
self.signal = WorkSignals()
def run(self):
self.signal.operation_started.emit(input)
self.q_ap
# Doing some operations
self.signal.operation_finished.emit(input)
self.q_app.processEvents()
class WorkSignals(QtCore.QObject):
operation_started = QtCore.pyqtSignal(str)
operation_finished= QtCore.pyqtSignal(str)
class StreamWorkThread (QtCore.QThread):
def __init__(self, inputs, q_app):
super(StreamWorkThread, self).__init()
self.signal = WorkSignals()
self.stream_pool = StreamPool(inputs,q_app)
self.stream_pool.signal.operation_started.connect(self.signal.operation_started.emit)
self.stream_pool.signal.operation_finished.connect(self.signal.operation_finished.emit)
def run(self):
self.stream_pool.start()
def print_start(name):
print 'Started --', name
def print_finished(name):
print 'Finished --', name
if __name__ == '__main__':
app = QtGui.QApplication([])
th = StreamWorkThread (['a', 'b', 'c'], app)
th.signal.operation_started.connect(print_start)
th.signal.operation_finshed.connect(print_finished)
th.start()
app.exec_()
Please guys help me, im not getting what exactly the problem here..! :(
Okay, I got the solution for this behavior.
The root cause of blocking the signal is inheriting QObject in StrealPool, when I replace QObject with QThread it worked seamlessly.
Here are the changes I made, only tow places
class StreamPool(**QtCore.QThread**):
def __inti__(self, inputs, q_app):
super(StreamPool, self).__init()
self.inputs = inputs
self.q_app = q_app
self.pool = QtCore.QThreadPool()
def **run**(self):
for each_input in self.inputs:
runner = StreamRunner(each_input, self.q_app)
runner.signal.operation_started.connect(self.mark_as_start)
runner.signal.operation_finished.connect(self.mark_as_start)
self.pool.start(runner)
and that set, it worked ! :D
very difficult without the source code, but the problem is probably when "app.exec_()" is run, the mainloop of the gui is started and interferes with your Streamx classes

PyQt4 QThread / moveToThread not working depending on context?

I'm trying to understand why the following code immediately exits, but works if I create the thread in the main context and not in a second object?
from PyQt4 import QtCore
import time
import sys
class SomeObject(QtCore.QObject):
finished = QtCore.pyqtSignal()
def longRunning(self):
count = 0
while count < 5:
time.sleep(1)
print "Increasing"
count += 1
self.finished.emit()
class SecondObject(QtCore.QObject):
def __init__(self, app):
QtCore.QObject.__init__(self)
objThread = QtCore.QThread()
obj = SomeObject()
obj.moveToThread(objThread)
obj.finished.connect(objThread.quit)
objThread.started.connect(obj.longRunning)
objThread.finished.connect(app.exit)
objThread.start()
def usingMoveToThread():
app = QtCore.QCoreApplication([])
SecondObject(app)
sys.exit(app.exec_())
if __name__ == "__main__":
usingMoveToThread()
Thanks in Advance for any help!
I've found the problem. Apparently you need to hold on to the new Thread's reference otherwise the Application will just quit...

Categories

Resources