Как я могу использовать QTextBrowser вместо консоли в Python?

Я создал окно в PyQt 5, в котором, нажав кнопку оптимизации, программа читает файл Gurobi-model.lp (щелкните здесь, чтобы получить файл) и оптимизирует его с помощью программного обеспечения Gurobi. Как я могу отобразить журналы Gurobi в QTextBrowser?

Я нашел в Gurobi некоторые функции, такие как OutputFlag, LogFile и LogToConsole. Могут ли эти функции быть полезными?

Для тех, кто не знаком с Gurobi, оптимизатор Gurobi использует Python в качестве интерфейса и создает несколько журналов, позволяющих отслеживать ход оптимизации. Эти логи печатаются в консоли во время оптимизации, и почему-то, отвечая на мой вопрос, не нужно ничего знать о Гуроби.

В приведенном ниже коде я нашел способ показать журналы в QTextBrowser, но журналы представлены, когда процесс оптимизации полностью завершен. Я хочу, чтобы логи отображались именно в процессе оптимизации.

import sys
from PyQt5.QtWidgets import *
from gurobipy import *
from io import *


class MyWindow(QWidget):

    def __init__(self):
        QWidget.__init__(self)

        self.pb = QPushButton(self.tr("optimize"))
        self.log_text = QTextBrowser()

        layout = QVBoxLayout(self)
        layout.addWidget(self.pb)
        layout.addWidget(self.log_text)
        self.setLayout(layout)

        self.pb.clicked.connect(self.optimize)

     def optimize(self):

        f = StringIO()
        sys.stdout = StringIO()

        self.m = read('Gurobi-model.lp')
        self.m.optimize()
        self.log_text.append(sys.stdout.getvalue() )


def main():
   app = QApplication(sys.argv)
   w = MyWindow()
   w.show()
   sys.exit(app.exec_())

if __name__ == "__main__":
    main()

person Hooman.AS    schedule 12.02.2019    source источник


Ответы (1)


Задача оптимизации тяжелая, поэтому ее нельзя выполнять в одном потоке графического интерфейса или в одном процессе. Для этого следует использовать модуль multiprocessing. С другой стороны, если вам нужно показать вывод консоли в QTextBrowser, вы должны использовать модуль ведения журнала, передавая его через сигнал (для последней части используйте ответ на этот пост).

import sys
import logging
import multiprocessing
from logging.handlers import QueueHandler, QueueListener
from PyQt5 import QtCore, QtWidgets
from gurobipy import *

class LogEmitter(QtCore.QObject):
    sigLog = QtCore.pyqtSignal(str)

class LogHandler(logging.Handler):
    def __init__(self):
        super().__init__()
        self.emitter = LogEmitter()

    def emit(self, record):
        msg = self.format(record)
        self.emitter.sigLog.emit(msg)

def long_task():
    m = read('Gurobi-model.lp')
    m.optimize()

def worker_init(q):
    qh = QueueHandler(q)
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    logger.addHandler(qh)

class MyWindow(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)

        self.pb = QtWidgets.QPushButton(self.tr("optimize"),
            clicked=self.start_optimize)
        self.log_text = QtWidgets.QPlainTextEdit(readOnly=True)

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.pb)
        layout.addWidget(self.log_text)

        self.running = False
        handler = LogHandler()
        handler.emitter.sigLog.connect(self.log_text.appendPlainText)

        self.q = multiprocessing.Queue()
        self.ql = QueueListener(self.q, handler)
        self.ql.start()

        self.main_log = logging.getLogger('main')
        self.main_log.propagate = False
        self.main_log.setLevel(logging.INFO)
        self.main_log.addHandler(QueueHandler(self.q))
        self.pool = multiprocessing.Pool(1, worker_init, [self.q])

    @QtCore.pyqtSlot()
    def start_optimize(self):
        if not self.running:
            self.pool.apply_async(long_task, callback=self.handle_result)

    def handle_result(self, result=None):
        self.running = False

    def closeEvent(self, event):
        self.ql.stop()
        super(MyWindow, self).closeEvent(event)

def main():
   app = QtWidgets.QApplication(sys.argv)
   w = MyWindow()
   w.show()
   sys.exit(app.exec_())

if __name__ == "__main__":
    main()
person eyllanesc    schedule 12.02.2019