I have written the following code that parses a text file, breaks it into tokens and inserts these tokens into the database. I want to show the current status of the process using the progress bar but the following code isn't working.
I wrote the following code based on this How to connect pyqtSignal between classes in PyQT
yast_gui.py
class YastGui(QtGui.QMainWindow):
incrementTokenSignal = QtCore.pyqtSignal(int)
...
def __init__(self):
self.incrementTokenSignal.connect(self.increment_token_count)
...
def increment_token_count(self, val):
msg = "{}/{}".format(val, self.total_db_records)
self.ui.records_processed_value_label.setText(msg)
yast.py
class LogFile(object):
def __init__(self, file_path, YastGui_object):
super(LogFile, self).__init__()
# Gui object
self.gui = YastGui_object
self.total_db_records = 0
...
def tokenize(self):
for i, record in enumerate(myfile):
...
self.gui.incrementFilterSignal.emit(i + 1)
settings.session.commit()
According to this PYQT and progress Bar during Long Process, I should create QTheads to deal with the progress bar but I'm not sure on how to do it.
Here is the entire Gui file and main file.
I found the solution to my problem here Change the value of the progress bar from a class other than my GUI class PyQt4.
The trick is to pass the progressBar object to the function as a parameter and then use progressBar.setValue() inside that function.
Related
According this example : link ,I want to implement a thread based small application within a GUI. I have two files TestMain.py and TestManager.py (Worker class), which are connected with each other over sys.path.append('...'). In TestMain.py, I load my GUI, create thread and signal/slot connections, which act on functions in TestManager.py. In TestManager.py I do some calculations and want to visualize them in a QTextEditor at the same time. To do this, I have written following code:
TestMain.py
sys.path.append('../app/source')
from TestManager import *
class TestMain(QMainWindow):
def __init__(self, parent= None):
super(TestMain, self).__init__(parent)
self.manager= TestManager()
self.thread= QThread()
self.manager.moveToThread(self.thread)
self.manager.finished.connect(self.thread.quit)
self.thread.started.connect(self.manager.first_slot)
self.thread.start()
self.manager.printFirstSignal.connect(self.print_onTextEdit)
self.offlinePushButton.clicked.connect(self.offline_slot)
def offline_slot(self):
manager.do_some_calc(self)
def print_onTextEdit(self, str):
self.outputTextEdit.append(str)
Manager.py
sys.path.append('../app/source')
from TestMain import *
class TestManager(QObject): #QtCore.QThread
finished= pyqtSignal()
printFirstSignal= pyqtSignal(str)
def __init__(self, parent= None):
super(TestManager, self).__init__(parent)
def first_slot(self):
self.printFirstSignal.emit('TEST')
self.finished.emit()
def do_some_calc(self):
do_someting()
TestManager.first_slot("do_some_calc")
If I do self.thread.started.connect(self.manager.first_slot) in TestMain and emit the pyqtSignal in function first_slot() in TestManager, then I can update my GUI without any problem. But if I call a slot (e.g do_some_calc()) in TestManager and want to also update the GUI from there, than I get a segmentation fault. Even if I create a separate signal for this function, it does not work. Cause I call this function in TestMain self.offlinePushButton.clicked.connect(self.offline_slot)
My question is. How can I call any function in TestManager internally or from MainTest so that I can still update the GUI?
Thank you for any suggestion
How do i pass variables from one python module(1st module) to another(2nd module) which contains a main module and two Qdialog which appears when the buttons are pressed in the 2nd module
How can i send these values from 1st module to the Qdialog in the 2nd module
I am dealing with multiple modules and data needs to updated here and there and totally confused with Inheritance/ Creating instances of classes and Modules
# mainwindow.py(1st module)
from 2nd_module import window2, dialog1, dialog2
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.win2 =window2()
self.dia1 =dialog1()
if 1:
self.win2.bar()
# pass data
self.dia1.some_function(data)
.
# 2nd_module.py
from mainwindow import mainwindow
class dialog1 (QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
def update(self):
w = window2()
#do something
w.self.ma.foo()
.
.
class dialog2 (QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
.
.
class window2(QtGui.QMainWindow):
def __init__(self):
super(window2, self).__init__()
self.update_request = 0 # initilizing the variable here
self.ma = mainwindow()
self.connect(dialog1_bttn, Qt.SIGNAL("clicked()"), self.open_dialog1 )
def open_dialog1(self): #this is how i create the instance of dialog box
self.open1 =dialog1()
self.open1.show
def foo(self): # this updates the request value from 2 dialog boxes
#do something
self.update_request = 1
def bar(self): # this is called from 1st module to check if there are any update requests
if self.update_request ==1:
#do something
My struggles
so here when i call foo() from dialog1 it works fine and updates the value to 1. But now when i call bar() from 1st module the value self.update_request turns to be 0 all the time
my mainwindow(1st module) runs all the background tasks like exchanging data from serial port,etc. and i need to send that data to the dialog1 in 2nd_module to update the values
Can anyone please advise me on how to create proper instances of Qt Dialogs, windows and to pass data/variables/list from one class to another ..thanks in advance
I'm managing some long running tasks using signals and slots to track progress and such. I had a Run class that starts like this:
from PySide import QtCore, QtGui
class Run(QtCore.QObject):
running = QtCore.Signal(bool)
finished = QtCore.Signal(object)
status = QtCore.Signal(str)
message = QtCore.Signal(object)
progress = QtCore.Signal(float)
time_remaining_update = QtCore.Signal(str)
initialized = QtCore.Signal()
failed = QtCore.Signal(object)
pitch_update = QtCore.Signal(float)
def __init__(self, parent=None):
super().__init__(parent=parent)
#... rest of the class ...
I recently refactored some things and wrote a Task class which includes a Run instance as an attribute. I would like to "echo" many of the Run's signals upstream. This is my current solution:
class Task(QtCore.QObject):
#Signals echoed from Run
running = QtCore.Signal(bool)
status = QtCore.Signal(str)
message = QtCore.Signal(object)
progress = QtCore.Signal(float)
time_remaining_update = QtCore.Signal(str)
initialized = QtCore.Signal()
def __init__(self, run, parent=None):
super().__init__(parent=parent)
self.run = run
#Echo signals from run
signals = ['running', 'status', 'message', 'progress', 'time_remaining_update', 'initialized']
for signal in signals:
#Re-emit the signal
getattr(self.run, signal).connect(lambda *args: getattr(self, signal).emit(*args))
#... rest of class ...
I confirmed that the lambda *args: func(*args) pattern will avoid passing anything to func if nothing is passed to the lambda, which is necessary to obey the different signals' signatures.
Is this the best way to handle "echoing" or "bouncing" signals from one QObject to another? I'm basically trying to preserve some of the Run API while changing/adding other aspects with my Task API.
I realize that I can get all of the Run API by subclassing and overriding things I want to change, but I didn't want to subclass since Task handles restarting the run after failure. I'd like to keep the run logic separate from the code that handles restarting the run. There are also Run signals and methods that I don't want propagated by Task.
The only more elegant solution I can think of is to automate the creation of the Task signals... maybe make a echo_signals decorator that takes a QObject and a list of signal names that then does these things?
Is there a Qt feature for implementing this more elegantly? Any suggestions?
In Qt you can connect signals to other signals, unless I'm missing something regarding your example.
My PyQt program has 2 widgets (selecting files etc) and then a Main Window which displays the results of the parsed files.
The program works great for small sample files, but when trying to parse larger files it will hang (display "Not Responding") and then show the results after about 30 seconds or so.
I would like to implement a QDialog before the Main Window opens. The QDialog will have a progress bar to let the user know when the Main Window will open.
This progress bar needs to be set to the length of time before the Main Window pops up.
What is the best way to implement this? I have seen some examples, but the progress bar is just set to a standardised time, not when the processing(parsing) is complete.
I currently have the following code which opens the Main Window.
def openWidgetMain(self):
self.WidgetMain = WidgetMain()
self.WidgetMain.show()
self.close()
All the processing for this window is done when it opens. So how do I connect the QProgressBar?
Put your long lasting process in some kind of thread. Read this: http://qt-project.org/doc/qt-5/threads-technologies.html
Emit a signal from that thread to update your progress bar. This way your application will not hang and the user sees the progress.
However it is up to your loading routine to decide which percentage to show in the progress bar. If you can't calculate an exact percentage try some kind of estimation (e.g. based on the size of the file vs. processed amount of the file).
First, best way to implement this, Your must estimate your load progress file. Next, implement it with QtCore.QThread to create background process. Last, put your call back progress into your QtGui.QMainWindow.
Little example;
import sys
import time
from PyQt4 import QtGui
from PyQt4 import QtCore
class QCustomThread (QtCore.QThread):
startLoad = QtCore.pyqtSignal(int)
progressLoad = QtCore.pyqtSignal(int)
statusLoad = QtCore.pyqtSignal(bool)
def __init__ (self, parentQWidget = None):
super(QCustomThread, self).__init__(parentQWidget)
self.wasCanceled = False
def run (self):
# Simulate data load estimation
numberOfprogress = 100
self.startLoad.emit(numberOfprogress)
for progress in range(numberOfprogress + 1):
# Delay
time.sleep(0.1)
if not self.wasCanceled:
self.progressLoad.emit(progress)
else:
break
self.statusLoad.emit(True if progress == numberOfprogress else False)
self.exit(0)
def cancel (self):
self.wasCanceled = True
class QCustomMainWindow (QtGui.QMainWindow):
def __init__ (self):
super(QCustomMainWindow, self).__init__()
# Create action with QPushButton
self.startQPushButton = QtGui.QPushButton('START')
self.startQPushButton.released.connect(self.startWork)
self.setCentralWidget(self.startQPushButton)
# Create QProgressDialog
self.loadingQProgressDialog = QtGui.QProgressDialog(self)
self.loadingQProgressDialog.setLabelText('Loading')
self.loadingQProgressDialog.setCancelButtonText('Cancel')
self.loadingQProgressDialog.setWindowModality(QtCore.Qt.WindowModal)
def startWork (self):
myQCustomThread = QCustomThread(self)
def startLoadCallBack (numberOfprogress):
self.loadingQProgressDialog.setMinimum(0)
self.loadingQProgressDialog.setMaximum(numberOfprogress)
self.loadingQProgressDialog.show()
def progressLoadCallBack (progress):
self.loadingQProgressDialog.setValue(progress)
def statusLoadCallBack (flag):
print 'SUCCESSFUL' if flag else 'FAILED'
myQCustomThread.startLoad.connect(startLoadCallBack)
myQCustomThread.progressLoad.connect(progressLoadCallBack)
myQCustomThread.statusLoad.connect(statusLoadCallBack)
self.loadingQProgressDialog.canceled.connect(myQCustomThread.cancel)
myQCustomThread.start()
myQApplication = QtGui.QApplication(sys.argv)
myQCustomMainWindow = QCustomMainWindow()
myQCustomMainWindow.show()
sys.exit(myQApplication.exec_())
More infomation of QtCore.QThread (Recommend read to understand behavior)
I'm trying to code something that downloads a file from a webserver and saves it, showing the download progress in a QProgressBar.
Now, there are ways to do this in regular Python and it's easy. Problem is that it locks the refresh of the progressBar. Solution is to use PyQT's QNetworkManager class. I can download stuff just fine with it, I just can't get the setup to show the progress on the progressBar. HereĀ“s an example:
class Form(QDialog):
def __init__(self,parent=None):
super(Form,self).__init__(parent)
self.progressBar = QProgressBar()
self.reply = None
layout = QHBoxLayout()
layout.addWidget(self.progressBar)
self.setLayout(layout)
self.manager = QNetworkAccessManager(self)
self.connect(self.manager,SIGNAL("finished(QNetworkReply*)"),self.replyFinished)
self.Down()
def Down(self):
address = QUrl("http://stackoverflow.com") #URL from the remote file.
self.manager.get(QNetworkRequest(address))
def replyFinished(self, reply):
self.connect(reply,SIGNAL("downloadProgress(int,int)"),self.progressBar, SLOT("setValue(int)"))
self.reply = reply
self.progressBar.setMaximum(reply.size())
alltext = self.reply.readAll()
#print alltext
#print alltext
def updateBar(self, read,total):
print "read", read
print "total",total
#self.progressBar.setMinimum(0)
#self.progressBar.setMask(total)
#self.progressBar.setValue(read)
In this case, my method "updateBar" is never called... any ideas?
Well you haven't connected any of the signals to your updateBar() method.
change
def replyFinished(self, reply):
self.connect(reply,SIGNAL("downloadProgress(int,int)"),self.progressBar, SLOT("setValue(int)"))
to
def replyFinished(self, reply):
self.connect(reply,SIGNAL("downloadProgress(int,int)"),self.updateBar)
Note that in Python you don't have to explicitly use the SLOT() syntax; you can just pass the reference to your method or function.
Update:
I just wanted to point out that if you want to use a Progress bar in any situation where your GUI locks up during processing, one solution is to run your processing code in another thread so your GUI receives repaint events. Consider reading about the QThread class, in case you come across another reason for a progress bar that does not have a pre-built solution for you.