This question seems to have been asked many times in many different forms but I haven't managed to find one with a -relevant to my code- solution.
When I run the program it shows
QObject::installEventFilter: Cannot filter events for objects in a different thread.
Despite this the code works initially but after a while it bombs and python gives an error saying its stopped working.
My code is as follows:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from xml.etree import ElementTree as ET
import os , time
class LayoutCreator(QDialog):
def __init__(self , parent=None):
super(LayoutCreator, self).__init__(parent)
self.Cameras_Update()
def Cameras_Update( self ): # Get all shots with camera plots and add them to the cameras_tree
busyBar = sqrl_QtTools.BusyBar( text = "Gathering Camera Data" ) # Looping progress bar
busyBar.start()
# loop through folder structure storing data
busyBar.Kill() # Close looping progress bar
class BusyBar(QThread): # Looping progress bar
def __init__(self, text = "" ):
QThread.__init__(self)
self.text = text
self.stop = False
def run( self ):
self.proBar = QProgressBar()
self.proBar.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.SplashScreen )
self.proBar.setMinimum( 0 )
self.proBar.setMaximum( 100 )
self.proBar.setTextVisible( True )
self.proBar.setFormat( self.text )
self.proBar.setValue( 0 )
self.proBar.setFixedSize( 500 , 50 )
self.proBar.setAlignment(Qt.AlignCenter)
self.proBar.show()
while not self.stop: # keep looping while self is visible
# Loop sending mail
for i in range(100):
progress = self.proBar.value()
progress = progress + 1
self.proBar.setValue( progress )
time.sleep(0.05)
self.proBar.setValue( 0 )
self.proBar.hide()
def Kill(self):
self.stop = True
You can't create or access any QWidget
outside the main thread.
You can use signals and slots to indirectly access widgets from the other thread:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, time
class BusyBar(QThread): # Looping progress bar
# create the signal that the thread will emit
changeValue = pyqtSignal(int)
def __init__(self, text = "" ):
QThread.__init__(self)
self.text = text
self.stop = False
self.proBar = QProgressBar()
self.proBar.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.SplashScreen )
self.proBar.setRange( 0, 100 )
self.proBar.setTextVisible( True )
self.proBar.setFormat( self.text )
self.proBar.setValue( 0 )
self.proBar.setFixedSize( 500 , 50 )
self.proBar.setAlignment(Qt.AlignCenter)
self.proBar.show()
self.changeValue.connect(self.proBar.setValue, Qt.QueuedConnection)
# Make the Busybar delete itself and the QProgressBar when done
self.finished.connect(self.onFinished)
def run( self ):
while not self.stop: # keep looping while self is visible
# Loop sending mail
for i in range(100):
# emit the signal instead of calling setValue
# also we can't read the progress bar value from the thread
self.changeValue.emit( i )
time.sleep(0.05)
self.changeValue.emit( 0 )
def onFinished(self):
self.proBar.deleteLater()
self.deleteLater()
def Kill(self):
self.stop = True
class LayoutCreator(QDialog):
def __init__(self , parent=None):
super(LayoutCreator, self).__init__(parent)
self.Cameras_Update()
def Cameras_Update( self ):
# Looping progress bar
self.busyBar = BusyBar( text = "Gathering Camera Data" )
self.busyBar.start()
# loop through folder structure storing data
# Simulate async activity that doesn't block the GUI event loop
# (if you do everything without giving control back to
# the event loop, you have to call QApplication.processEvents()
# to allow the GUI to update itself )
QTimer.singleShot(10000, self.stopBar)
def stopBar(self):
self.busyBar.Kill() # Close looping progress bar
app = QApplication(sys.argv)
win = LayoutCreator()
win.show();
sys.exit(app.exec_())
Or
If you only want a busy indicator, you can simply set both the minimum and maximum of the QProgressBar
to 0, and you won't need a thread, as indicated in the documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With