Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
472eced6
Commit
472eced6
authored
Jul 31, 2019
by
Vinay Sajip
Committed by
GitHub
Jul 31, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refined Qt GUI example in the logging cookbook. (GH-15045)
parent
d04f8907
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
39 additions
and
17 deletions
+39
-17
Doc/howto/logging-cookbook.rst
Doc/howto/logging-cookbook.rst
+39
-17
No files found.
Doc/howto/logging-cookbook.rst
View file @
472eced6
...
...
@@ -2760,8 +2760,8 @@ The following example shows how to log to a Qt GUI. This introduces a simple
``QtHandler`` class which takes a callable, which should be a slot in the main
thread that does GUI updates. A worker thread is also created to show how you
can log to the GUI from both the UI itself (via a button for manual logging)
as well as a worker thread doing work in the background (here, just
random
short delays
).
as well as a worker thread doing work in the background (here, just
logging
messages at random levels with random short delays in between
).
The worker thread is implemented using Qt's ``QThread`` class rather than the
:mod:`threading` module, as there are circumstances where one has to use
...
...
@@ -2769,7 +2769,7 @@ The worker thread is implemented using Qt's ``QThread`` class rather than the
The code should work with recent releases of either ``PySide2`` or ``PyQt5``.
You should be able to adapt the approach to earlier versions of Qt. Please
refer to the comments in the code for more detailed information.
refer to the comments in the code
snippet
for more detailed information.
.. code-block:: python3
...
...
@@ -2789,22 +2789,24 @@ refer to the comments in the code for more detailed information.
Signal = QtCore.pyqtSignal
Slot = QtCore.pyqtSlot
logger = logging.getLogger(__name__)
#
# Signals need to be contained in a QObject or subclass in order to be correctly
# initialized.
#
class Signaller(QtCore.QObject):
signal = Signal(str)
signal = Signal(str
, logging.LogRecord
)
#
# Output to a Qt GUI is only supposed to happen on the main thread. So, this
# handler is designed to take a slot function which is set up to run in the main
# thread. In this example, the function takes a s
ingle
argument which is a
# formatted log message
. You can attach a formatter instance which formats a
#
LogRecord however you like, or change the slot function to take some other
#
value derived from the LogRecord
.
# thread. In this example, the function takes a s
tring
argument which is a
# formatted log message
, and the log record which generated it. The formatted
#
string is just a convenience - you could format a string for output any way
#
you like in the slot function itself
.
#
# You specify the slot function to do whatever GUI updates you want. The handler
# doesn't know or care about specific UI elements.
...
...
@@ -2817,7 +2819,7 @@ refer to the comments in the code for more detailed information.
def emit(self, record):
s = self.format(record)
self.signaller.signal.emit(s)
self.signaller.signal.emit(s
, record
)
#
# This example uses QThreads, which means that the threads at the Python level
...
...
@@ -2827,6 +2829,13 @@ refer to the comments in the code for more detailed information.
def ctname():
return QtCore.QThread.currentThread().objectName()
#
# Used to generate random levels for logging.
#
LEVELS = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,
logging.CRITICAL)
#
# This worker class represents work that is done in a thread separate to the
# main thread. The way the thread is kicked off to do work is via a button press
...
...
@@ -2851,7 +2860,8 @@ refer to the comments in the code for more detailed information.
while not QtCore.QThread.currentThread().isInterruptionRequested():
delay = 0.5 + random.random() * 2
time.sleep(delay)
logger.debug('Message after delay of %3.1f: %d', delay, i, extra=extra)
level = random.choice(LEVELS)
logger.log(level, 'Message after delay of %3.1f: %d', delay, i, extra=extra)
i += 1
#
...
...
@@ -2864,10 +2874,18 @@ refer to the comments in the code for more detailed information.
#
class Window(QtWidgets.QWidget):
COLORS = {
logging.DEBUG: 'black',
logging.INFO: 'blue',
logging.WARNING: 'orange',
logging.ERROR: 'red',
logging.CRITICAL: 'purple',
}
def __init__(self, app):
super(Window, self).__init__()
self.app = app
self.textedit = te = QtWidgets.QTextEdit(self)
self.textedit = te = QtWidgets.Q
Plain
TextEdit(self)
# Set whatever the default monospace font is for the platform
f = QtGui.QFont('nosuchfont')
f.setStyleHint(f.Monospace)
...
...
@@ -2880,7 +2898,7 @@ refer to the comments in the code for more detailed information.
self.handler = h = QtHandler(self.update_status)
# Remember to use qThreadName rather than threadName in the format string.
fs = '%(asctime)s %(qThreadName)-12s %(levelname)-8s %(message)s'
formatter = logging.Formatter(f)
formatter = logging.Formatter(f
s
)
h.setFormatter(formatter)
logger.addHandler(h)
# Set up to terminate the QThread when we exit
...
...
@@ -2932,14 +2950,17 @@ refer to the comments in the code for more detailed information.
# that's where the slots are set up
@Slot(str)
def update_status(self, status):
self.textedit.append(status)
def update_status(self, status, record):
color = self.COLORS.get(record.levelno, 'black')
s = '<pre><font color="
%
s
">%s</font></pre>' % (color, status)
self.textedit.appendHtml(s)
@Slot()
def manual_update(self):
levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,
logging.CRITICAL)
level = random.choice(levels)
# This function uses the formatted message passed in, but also uses
# information from the record to format the message in an appropriate
# color according to its severity (level).
level = random.choice(LEVELS)
extra = {'qThreadName': ctname() }
logger.log(level, 'Manually logged!', extra=extra)
...
...
@@ -2947,6 +2968,7 @@ refer to the comments in the code for more detailed information.
def clear_display(self):
self.textedit.clear()
def main():
QtCore.QThread.currentThread().setObjectName('MainThread')
logging.getLogger().setLevel(logging.DEBUG)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment