Мне потребовалось много времени, чтобы опубликовать здесь свой первый вопрос, так как все ответы на все вопросы, которые у меня были в прошлом, уже здесь. Но я еще не нашел решения этой проблемы, так что начнем:
ОПИСАНИЕ: В моем приложении я хочу отображать информацию журнала в реальном времени в виджете QTextEdit. Чтобы заставить это работать, я реализовал решение, которое нашел здесь.
ПРОБЛЕМА: Код в приведенной выше ссылке работает как шарм, пока все выполняемые функции являются частью основного класса Window. Но для моего приложения мне нужно, чтобы это работало вне основного модуля. Я хочу иметь возможность получать информацию журнала в реальном времени (строка за строкой) из внешних функций (например: когда функция «someProcess» находится в другом модуле, см. код ниже). Когда я пытаюсь это сделать, все работает, но он не отображает строку информации журнала на строку, как это было раньше, а все строки сразу после завершения внешней функции.
Я предполагаю, что это логично, потому что во внешней функции нет сигнала, исходящего от объекта логгера во внешнем модуле. Но я не могу обдумать простой (или любой) способ сделать это.
import sys
import time
import logging
import othermodule as om
from PyQt5.QtCore import QObject, pyqtSignal, QThread
from PyQt5.QtWidgets import QWidget, QTextEdit, QPushButton, QVBoxLayout, QApplication
logger = logging.getLogger(__name__)
class ConsoleWindowLogHandler(logging.Handler, QObject):
sigLog = pyqtSignal(str)
def __init__(self):
logging.Handler.__init__(self)
QObject.__init__(self)
def emit(self, logRecord):
message = str(logRecord.getMessage())
self.sigLog.emit(message)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
# Layout
textBox = QTextEdit()
textBox.setReadOnly(True)
self.button = QPushButton('Click')
vertLayout = QVBoxLayout()
vertLayout.addWidget(textBox)
vertLayout.addWidget(self.button)
self.setLayout(vertLayout)
# Connect button
self.button.clicked.connect(self.buttonPressed)
# Thread
self.bee = Worker(self.test, ())
self.bee.finished.connect(self.restoreUi)
self.bee.terminate()
# Console handler
consoleHandler = ConsoleWindowLogHandler()
consoleHandler.sigLog.connect(textBox.append)
logger.addHandler(consoleHandler)
def buttonPressed(self):
self.button.setEnabled(False)
self.bee.start()
def restoreUi(self):
self.button.setEnabled(True)
def test(self):
logger.error('Starting')
om.someProcess()
class Worker(QThread):
def __init__(self, func, args):
super(Worker, self).__init__()
self.func = func
self.args = args
def run(self):
self.func(*self.args)
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
import time
import logging
logger = logging.getLogger(__name__)
def someProcess(self):
logger.error("starting")
for i in range(10):
logger.error("line%d" % i) # Every iteration, I want to display this line per line
# in the textbox on the main window
time.sleep(2) # in my own code, here comes a time consuming task
Ошибка вызвана тем, что ConsoleWindowLogHandler обрабатывает только информацию регистратора, созданного в main.py, но не информацию, созданную в othermodule.py, решение состоит в том, чтобы назначить ConsoleWindowLogHandler также обработчиком регистратора, созданного в othermodule.py:
# Console handler
consoleHandler = ConsoleWindowLogHandler()
consoleHandler.sigLog.connect(textBox.append)
logger.addHandler(consoleHandler)
om.logger.addHandler(consoleHandler)
Note: Although it is trivial you should change def someProcess(self):
to def someProcess():