Так сложилось, что пользователям нужны графические интерфейсы. Виноваты в этом Microsoft, Apple или природа человека, которому удобней манипулировать визуальными объектами, может быть, и что-либо ещё, но факт остается фактом - программистам удобно и правильно использовать консольные приложения, а пользователям, будьте добры, предоставьте окошечки с кнопочками.
И так, ситуация: имеется уже написанное и отлаженное консольное приложение, необходимо предоставить к нему графический интерфейс. Один из вариантов на python+PyQt под катом.
Создадим простейшее приложение с графическим интерфейсом, которое позволит запускать произвольное консольное приложение с выводом его стандартных потоков stdout и stderr в QTextEdit.
В Qt Disigner создадим простую форму с полем для имени программы, опций и преобразуем в python-исходник с помощью pyuic4.
Далее, в конец метода инициализации формы setupUi добавляем:
self.process = QProcess()
self.process.readyReadStandardOutput.connect(self.readOutput)
self.process.readyReadStandardError.connect(self.readErrors)
self.process.finished.connect(self.finishedProcess)
self.pushButtonStart.clicked.connect(self.start)
self.pushButtonStop.clicked.connect(self.stop)
Здесь мы создаем экземпляр процесса и соединяем его сигналы readyReadStandardOutput, readyReadStandardError и finished с методами, которые опишем позже. Также зададим обработчики для нажатий кнопок. Кнопка Stop позволит нам принудительно прервать выполнение процесса.
Сигналы readyReadStandardOutput и readyReadStandardError позволяют нам узнать, когда приложение, запущенное в созданном процессе QProcess, записывает данные в стандартные потоки вывода типа stdout и stderr. Сигнал finished позволит нам узнать о завершении работы приложения и прочитать возвращаемое значение. Принято, что значение статуса "0" соответствует успешному завершению работы приложения, статус, отличный от нуля, - коду ошибки. Хотя, конечно, это зависит от автора этого приложения.
Функции запуска и останова выглядят следующим образом:
def start(self):
self.process.start(self.lineEditCommand.text(), \
self.lineEditOptions.text().split(" "))
self.process.waitForStarted()
def stop(self):
self.process.close()
self.process.waitForFinished()
Имхо, всё очень просто, пояснений не требуется.
Функции вывода данных потока также очень просты.
def outLogLine(self, line, color = Qt.black):
self.textEditLog.moveCursor(QTextCursor.End)
self.textEditLog.setTextColor(color)
self.textEditLog.insertPlainText(line)
c = self.textEditLog.textCursor();
c.movePosition(QTextCursor.End);
self.textEditLog.setTextCursor(c);
def readOutput(self):
output = self.process.readAllStandardOutput()
output = QTextCodec.codecForName('cp866').toUnicode(output)
self.outLogLine(output, Qt.darkGreen)
def readErrors(self):
output = self.process.readAllStandardError()
output = QTextCodec.codecForName('cp866').toUnicode(output)
self.outLogLine(output, Qt.red)
Нюанса два: во-первых, поскольку в винде, например, кодировка вывода консольных приложений cp-866, то необходима соответствующая перекодировка в unicode, во-вторых, курсор в QTextEdit устанавливаем с помощью setTextCursor, чтобы была автоматическая прокрутка лога на конец.
В общем, вот и всё. База для GUI-обертки любого консольного приложения готова. Исходник здесь. Всем удачи.
Хорошая статья здесь: Capturing Output from a Process.
Комментариев нет:
Отправить комментарий