mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	Refined Qt GUI example in the logging cookbook. (GH-15045)
This commit is contained in:
		
							parent
							
								
									d04f8907ba
								
							
						
					
					
						commit
						472eced677
					
				
					 1 changed files with 39 additions and 17 deletions
				
			
		|  | @ -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 single 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 string 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.QPlainTextEdit(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(fs) | ||||
|             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) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinay Sajip
						Vinay Sajip