如何在 Python 中使用 QTextBrowser 而不是控制台?
How can I use a QTextBrowser instead of the console in Python?
我在 PyQt 5 中构建了一个 window,通过单击“优化”按钮,程序读取“Gurobi-model.lp”文件 (click here to get the file),并且借助Gurobi软件对其进行优化。如何在 QTextBrowser 上显示 Gurobi 的日志?
我在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()
优化的任务很重,所以不要在GUI的同一个线程中执行,也不要在同一个进程中执行。为此,您应该使用多处理模块。另一方面,如果你需要在 QTextBrowser 中显示控制台的输出,你必须使用日志模块,通过信号传递它(对于最后一部分,使用这个 post 的 ) .
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()
我在 PyQt 5 中构建了一个 window,通过单击“优化”按钮,程序读取“Gurobi-model.lp”文件 (click here to get the file),并且借助Gurobi软件对其进行优化。如何在 QTextBrowser 上显示 Gurobi 的日志?
我在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()
优化的任务很重,所以不要在GUI的同一个线程中执行,也不要在同一个进程中执行。为此,您应该使用多处理模块。另一方面,如果你需要在 QTextBrowser 中显示控制台的输出,你必须使用日志模块,通过信号传递它(对于最后一部分,使用这个 post 的
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()