A code posted on Redirecting Output in PyQt does two good things at once: it takes advantage of logging
module to nicely format messages and it redirects standard stdout
and stderr
in to QT QTextBrowser
widget.
But I would like QTextBrowser
to receive all the print output coming out of running code. Particularly I want to redirect the nicely formatted messages that come from logger.
An ideal solution would re-direct every logger. output in to QTextBrowser
(and not just stdout
and stderr
). As a matter of fact I would rather redirect logger's messages instead of stdout
and stderr
ones if I would have to make a choice between the twos....
So here are the commands used to printout formatted messages:
logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
And here is the code:
========
import sys
from PyQt4 import QtCore, QtGui
import logging
logger = logging.getLogger(__name__)
class XStream(QtCore.QObject):
_stdout = None
_stderr = None
messageWritten = QtCore.pyqtSignal(str)
def flush( self ):
pass
def fileno( self ):
return -1
def write( self, msg ):
if ( not self.signalsBlocked() ):
self.messageWritten.emit(unicode(msg))
@staticmethod
def stdout():
if ( not XStream._stdout ):
XStream._stdout = XStream()
sys.stdout = XStream._stdout
return XStream._stdout
@staticmethod
def stderr():
if ( not XStream._stderr ):
XStream._stderr = XStream()
sys.stderr = XStream._stderr
return XStream._stderr
class MyDialog(QtGui.QDialog):
def __init__( self, parent = None ):
super(MyDialog, self).__init__(parent)
self._console = QtGui.QTextBrowser(self)
self._button = QtGui.QPushButton(self)
self._button.setText('Test Me')
layout = QtGui.QVBoxLayout()
layout.addWidget(self._console)
layout.addWidget(self._button)
self.setLayout(layout)
XStream.stdout().messageWritten.connect( self._console.insertPlainText )
XStream.stderr().messageWritten.connect( self._console.insertPlainText )
self._button.clicked.connect(self.test)
def test( self ):
print 'printing LINE 1'
print 'printing LINE 2'
logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
# error out something
print blah
if ( __name__ == '__main__' ):
# logging.basicConfig()
# logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.basicConfig(level=logging.DEBUG)
app = None
if ( not QtGui.QApplication.instance() ):
app = QtGui.QApplication([])
dlg = MyDialog()
dlg.show()
if ( app ):
app.exec_()
import sys
from PyQt4 import QtCore, QtGui
import logging
class QtHandler(logging.Handler):
def __init__(self):
logging.Handler.__init__(self)
def emit(self, record):
record = self.format(record)
if record: XStream.stdout().write('%s\n'%record)
# originally: XStream.stdout().write("{}\n".format(record))
logger = logging.getLogger(__name__)
handler = QtHandler()
handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
class XStream(QtCore.QObject):
_stdout = None
_stderr = None
messageWritten = QtCore.pyqtSignal(str)
def flush( self ):
pass
def fileno( self ):
return -1
def write( self, msg ):
if ( not self.signalsBlocked() ):
self.messageWritten.emit(unicode(msg))
@staticmethod
def stdout():
if ( not XStream._stdout ):
XStream._stdout = XStream()
sys.stdout = XStream._stdout
return XStream._stdout
@staticmethod
def stderr():
if ( not XStream._stderr ):
XStream._stderr = XStream()
sys.stderr = XStream._stderr
return XStream._stderr
class MyDialog(QtGui.QDialog):
def __init__( self, parent = None ):
super(MyDialog, self).__init__(parent)
self._console = QtGui.QTextBrowser(self)
self._button = QtGui.QPushButton(self)
self._button.setText('Test Me')
layout = QtGui.QVBoxLayout()
layout.addWidget(self._console)
layout.addWidget(self._button)
self.setLayout(layout)
XStream.stdout().messageWritten.connect( self._console.insertPlainText )
XStream.stderr().messageWritten.connect( self._console.insertPlainText )
self._button.clicked.connect(self.test)
def test( self ):
logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
print 'Old school hand made print message'
if ( __name__ == '__main__' ):
app = None
if ( not QtGui.QApplication.instance() ):
app = QtGui.QApplication([])
dlg = MyDialog()
dlg.show()
if ( app ):
app.exec_()
So the other approach I found is to redirect stderr in the same stream/queue stdout is redirected to. Since tqdm writes to stderr by default, this way all tqdm outputs are redirected to widget.
3 4 5 Thread Modes [PyQt] Newbe question about Print() to PyQt TimW Unladen Swallow Posts: 4 Threads: 1 Joined: Dec 2017 Reputation: 0 #1 Dec-18-2017, 10:32 PM
I've been programming in Python for almost 10 years. I did many CLI tools, some web applications (mainly using Flask ), but I had never built a GUI. PyQt seems to be one of the most popular framework. I had a look at it but I was not hooked. It looks like you really need to embrace the Qt world.
However, only logger lines are redirected. TQDM progress bar is still directed to the console output. Here is my current code:
The answer given by dano works for 2.7.x, but not for 3.x.
To get the code provided by @dano working in 3.4.3 I had to make the obvious changes to the print statements and also change the write() method in the XStream class from self.messageWritten.emit(unicode(msg))
to self.messageWritten.emit(msg)
. That unicode call just made the dialog sit there and stare back at me in amusement.
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