I'm new to PyQt and handlers in general, I tried to read from every repo I found but I can't figure out how to fix my issue, as you can see in my code, I'm executing logging thread in the background and I'm trying to show the logs in my QPlainTextEdit console - for some reason I can see the logs in my terminal and the text_box doesn't get the logs at all, I will appreciate a lot your smart help.
import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
import os
import threading
import json
class ConsolePanelHandler(logging.Handler):
def __init__(self, stream):
# super().__init__()
logging.Handler.__init__(self)
# logging.StreamHandler.__init__(self, stream)
self.stream = stream
def handle(self, record):
rv = self.filter(record)
if rv:
self.acquire()
try:
self.emit(record)
finally:
self.release()
return rv
def emit(self, record):
try:
stream = self.stream
stream(self.format(record))
except RecursionError:
raise
except Exception:
self.handleError(self.format(record))
def thread():
for index in range(20):
logging.warning('scheiBe ' str(index))
time.sleep(1)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.continue_ = QPushButton("Continue")
self.continue_.setStyleSheet("background-color: green")
self.continue_.setFont(QFont('SansSerif', 10))
self.continue_.setFixedSize(QSize(300, 22))
self.pause = QPushButton("Pause")
self.pause.setStyleSheet("background-color: orange")
self.pause.setFont(QFont('SansSerif', 10))
self.pause.setFixedSize(QSize(300, 22))
self.stop = QPushButton("Stop")
self.stop.setStyleSheet("background-color: #FD4B4B")
self.stop.setFont(QFont('SansSerif', 10))
self.stop.setFixedSize(QSize(300, 22))
self.text_box = QPlainTextEdit()
self.text_box.setPlaceholderText("Bugs will be printed here")
self.text_box.setReadOnly(True)
logging.getLogger().addHandler(self.text_box)
logging.getLogger().setLevel(logging.DEBUG)
ConsolePanelHandler(self.appendDebug , logging.DEBUG)
self.text_box.moveCursor(QTextCursor.End)
layout.addWidget(self.continue_)
layout.addWidget(self.pause)
layout.addWidget(self.stop)
layout.addWidget(self.text_box)
self.w = QWidget()
self.w.setLayout(layout)
self.setCentralWidget(self.w)
thread1 = threading.Thread(target=thread, args=(), daemon=True)
thread1.start()
self.show()
def closeEvent(self, event):
close = QMessageBox()
close.setText("Are you sure want to stop and exit?")
close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
close = close.exec()
if close == QMessageBox.Yes:
sys.exit()
else:
event.ignore()
def appendDebug(self, string):
self.text_box.appendPlainText(string '\n')
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
sys.exit(app.exec())
CodePudding user response:
First, you should not pass the function that updates the text_area
instead you should create a pyqtSignal
which updates the text_area
and pass it to ConsolePanelHandler
.
Add ConsolePanelHandler
as handler not text_area
to logging.getLogger().addHandler()
and it is recommended to use QThread
instead of threading.Thread
here is the complete updated code.
# import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
import os
import sys
import threading
import json
import logging
class ConsolePanelHandler(logging.Handler):
def __init__(self, sig):
# super().__init__()
logging.Handler.__init__(self)
# logging.StreamHandler.__init__(self, stream)
self.stream = sig
def handle(self, record):
rv = self.filter(record)
if rv:
self.acquire()
try:
self.emit(record)
finally:
self.release()
return rv
def emit(self, record):
try:
self.stream.emit(self.format(record))
except RecursionError:
raise
except Exception:
self.handleError(record)
class thread(QThread):
def run(self) -> None:
for index in range(20):
logging.warning('scheiBe ' str(index))
self.sleep(1)
class MainWindow(QMainWindow):
sig = pyqtSignal(str)
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.continue_ = QPushButton("Continue")
self.continue_.setStyleSheet("background-color: green")
self.continue_.setFont(QFont('SansSerif', 10))
self.continue_.setFixedSize(QSize(300, 22))
self.pause = QPushButton("Pause")
self.pause.setStyleSheet("background-color: orange")
self.pause.setFont(QFont('SansSerif', 10))
self.pause.setFixedSize(QSize(300, 22))
self.stop = QPushButton("Stop")
self.stop.setStyleSheet("background-color: #FD4B4B")
self.stop.setFont(QFont('SansSerif', 10))
self.stop.setFixedSize(QSize(300, 22))
self.c = ConsolePanelHandler(self.sig)
self.text_box = QPlainTextEdit()
self.text_box.setPlaceholderText("Bugs will be printed here")
self.text_box.setReadOnly(True)
logging.getLogger().addHandler(self.c)
logging.getLogger().setLevel(logging.DEBUG)
self.sig.connect(self.appendDebug)
self.text_box.moveCursor(QTextCursor.End)
self.layout.addWidget(self.continue_)
self.layout.addWidget(self.pause)
self.layout.addWidget(self.stop)
self.layout.addWidget(self.text_box)
self.w = QWidget()
self.w.setLayout(self.layout)
self.setCentralWidget(self.w)
self.thread1 = thread(self) # self is parent for Qthread so Qthread will be destroyed when it's parent no longer exist
self.thread1.start()
self.show()
def closeEvent(self, event):
close = QMessageBox()
close.setText("Are you sure want to stop and exit?")
close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
close = close.exec()
if close == QMessageBox.Yes:
self.thread1.terminate()
sys.exit()
else:
event.ignore()
@pyqtSlot(str)
def appendDebug(self, string):
self.text_box.appendPlainText(string '\n')
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
sys.exit(app.exec())