Как использовать QTextBrowser вместо консоли в Python? - PullRequest
0 голосов
/ 12 февраля 2019

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

Я нашел некоторые функции в Gurobi, такие как OutputFlag, LogFile, LogToConsole.Однако я много искал и не понимал, могут ли эти функции быть полезными для меня или нет.Кто-нибудь может мне помочь в этом отношении?

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

В приведенном ниже коде я нашел способ показать журналы в 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()

1 Ответ

0 голосов
/ 12 февраля 2019

задача оптимизации трудна, поэтому ее не следует выполнять ни в одном потоке графического интерфейса, ни в одном и том же процессе, для этого вам следует использовать модуль многопроцессорной обработки, с другой стороны, если вам нужно показать выходные данныеНа консоли в 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()
...