class MainWindow(QMainWindow): def __init__(self): # QMainWindow.__init__(self) super().__init__() # use super() to avoid explicit dependency on the base class name # Note: must not pass the self reference to __init__ in this case! self.resize(800, 600) # Create the main content widget mainWidget = QWidget(self) self.setCentralWidget(mainWidget) # Create a text component at the top area of the main widget self.output = QTextEdit(mainWidget) self.output.setReadOnly(True) self.output.setLineWrapMode(QTextEdit.NoWrap); # set the font font = self.output.font() font.setFamily("Courier") font.setPointSize(10) self.output.setFont(font) # Set the background color # self.output.setTextBackgroundColor(Qt.red) # Only sets the background color for the text itself, not for the whole widget pal = self.output.palette() pal.setColor(QPalette.Base, Qt.black) self.output.setPalette(pal) mainLayout = QVBoxLayout(mainWidget) mainLayout.addWidget(self.output) # Create buttons in a grid layout below the top area buttonWidget = QWidget(mainWidget) self.buttonLayout = QGridLayout(buttonWidget) mainLayout.addWidget(buttonWidget) # Add some buttons to execute python code self.row = 0 self.column = 0 self.addButton("Clear console", lambda : self.output.clear()) self.newRow() # Add buttons for all the examples - attention: do not make "examples" # a local variable - otherwise, the Examples object would be destroyed # at the end of __init__ !!! self.examples = samplePackage.SampleModule.Examples(self) for example in self.examples.getExamples(): if example is None: self.newRow() else: self.addButton(example.label, example.function) # In a Python program, sys.excepthook is called just before the program exits. # So we can catch all fatal, uncaught exceptions and log them. # NOTE: we must be sure not to set the excepthook BEFORE we an actually # log something!! sys.excepthook = self.logException self.writelnColor(Qt.magenta, "Python version: {0}.{1}.{2} ({3})".format( sys.version_info[0], sys.version_info[1], sys.version_info[2], sys.version_info[3])) self.writelnColor(Qt.magenta, "Qt version : {0}".format(qVersion())) def logException(self, exctype, value, tb): self.writelnColor(Qt.red, ("\nFATAL ERROR: Uncaught exception\n" " {}: {}\n" "{}\n".format(exctype.__name__, value, ''.join(traceback.format_tb(tb)))) ) def addButton(self, label, function): theButton = QPushButton(label) theButton.clicked.connect(function) self.buttonLayout.addWidget(theButton, self.row, self.column) self.column += 1 def newRow(self): self.row += 1 self.column = 0 def writeColor(self, color, *text): theText = ' '.join(map(str, text)) self.output.setTextColor(color) # Note: append() adds a new paragraph! #self.output.append(theText) self.output.textCursor().movePosition(QTextCursor.End) self.output.insertPlainText(theText) # scroll console window to bottom sb = self.output.verticalScrollBar() sb.setValue(sb.maximum()) def write(self, *text): self.writeColor(Qt.green, *text) def writelnColor(self, color, *text): self.writeColor(color, *text) self.write('\n') def writeln(self, *text): self.writelnColor(Qt.green, *text)
class QLogger(logging.Handler): '''Code from: https://stackoverflow.com/questions/28655198/best-way-to-display-logs-in-pyqt ''' def __init__(self, parent=None, format=settings.log_fmt, level=logging.INFO): logging.Handler.__init__(self) # Initialize a log handler as the super class self.setFormatter(logging.Formatter(format)) # Set the formatter for the logger self.setLevel(level) # Set the logging level self.frame = QFrame(parent) # Initialize a QFrame to place other widgets in self.frame2 = QFrame(parent) # Initialize frame2 for the label and checkbox self.label = QLabel('Logs') # Define a label for the frame self.check = QCheckBox('Debugging') # Checkbox to enable debugging logging self.check.clicked.connect(self.__changeLevel) # Connect checkbox clicked to the __changeLevel method self.log_widget = QTextEdit() # Initialize a QPlainTextWidget to write logs to self.log_widget.verticalScrollBar().minimum() # Set a vertical scroll bar on the log widget self.log_widget.horizontalScrollBar().minimum() # Set a horizontal scroll bar on the log widget self.log_widget.setLineWrapMode(self.log_widget.NoWrap) # Set line wrap mode to no wrapping self.log_widget.setFont(QFont("Courier", 12)) # Set the font to a monospaced font self.log_widget.setReadOnly(True) # Set log widget to read only layout = QHBoxLayout() # Initialize a horizontal layout scheme for the label and checkbox frame layout.addWidget(self.label) # Add the label to the layout scheme layout.addWidget(self.check) # Add the checkbox to the layout scheme self.frame2.setLayout(layout) # Set the layout for frame to the horizontal layout layout = QVBoxLayout() # Initialize a layout scheme for the widgets layout.addWidget(self.frame2) # Add the label/checkbox frame to the layout scheme layout.addWidget(self.log_widget) # Add the text widget to the layout scheme self.frame.setLayout(layout) # Set the layout of the fram to the layout scheme defined ############################################################################## def emit(self, record): ''' Overload the emit method so that it prints to the text widget ''' msg = self.format(record) # Format the message for logging if record.levelno >= logging.CRITICAL: # If the log level is critical self.log_widget.setTextColor(Qt.red) # Set text color to red elif record.levelno >= logging.ERROR: # Elif level is error self.log_widget.setTextColor(Qt.darkMagenta) # Set text color to darkMagenta elif record.levelno >= logging.WARNING: # Elif level is warning self.log_widget.setTextColor(Qt.darkCyan) # Set text color to darkCyan else: # Else self.log_widget.setTextColor(Qt.black) # Set text color to black self.log_widget.append(msg) # Add the log to the text widget ############################################################################## def write(self, m): ''' Overload the write method so that it does nothing ''' pass ############################################################################## def __changeLevel(self, *args): ''' Private method to change logging level ''' if self.check.isChecked(): self.setLevel(logging.DEBUG) # Get the Meso1819 root logger and add the handler to it else: self.setLevel(logging.INFO)