Как использовать терминал, встроенный в графический интерфейс PyQt

Существует существующая среда и инфраструктура, которую можно использовать через терминал Bash, вокруг которой я хочу создать графический интерфейс. Я имею в виду следующий поток:

  • В сеансе Bash создается среда среды. Это приводит ко всему: от переменных среды до аутентификаций, устанавливаемых в сеансе.
  • Сценарий Python GUI запускается для того, чтобы обернуть существующий сеанс и упростить выполнение последующих шагов.
  • Появляется графический интерфейс, отображающий с одной стороны сеанс Bash во встроенном терминале, а с другой стороны - набор кнопок, соответствующих различным командам, которые можно запускать в существующей среде платформы.
  • В графическом интерфейсе можно нажимать кнопки, что приводит к запуску определенных команд Bash. Результаты прогонов отображаются во встроенном терминале.

Каков хороший подход к созданию такого графического интерфейса? Я понимаю, что идея взаимодействия с существующей средой может быть сложной. Если это особенно сложно, я открыт для воссоздания среды в сеансе графического интерфейса. В любом случае, как GUI может взаимодействовать со встроенным терминалом. Как можно запускать команды и отображать их во встроенном терминале при нажатии кнопок графического интерфейса?

Основное начало графического интерфейса пользователя (со встроенным терминалом) выглядит следующим образом:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class embeddedTerminal(QWidget):

    def __init__(self):

        QWidget.__init__(self)
        self.resize(800, 600)
        self.process  = QProcess(self)
        self.terminal = QWidget(self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.terminal)
        self.process.start(
            'xterm',
            ['-into', str(self.terminal.winId())]
        )

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = embeddedTerminal()
    main.show()
    sys.exit(app.exec_())

Как я мог бежать, скажем, top на этом встроенном терминале после нажатия кнопки в графическом интерфейсе?

1 ответ

Решение

Если это должен быть реальный терминал и реальная оболочка (а не просто принимать строку ввода, запускать какую-то команду, а затем отображать вывод) - как насчет tmux?

Вы могли бы использовать что-то вроде tee чтобы получить результат обратно в вашу программу.

Обратите внимание, что сеансы tmux могут сохраняться во время выполнения вашей программы, поэтому вам нужно прочитать о том, как это работает и как его контролировать.

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class embeddedTerminal(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        self._processes = []
        self.resize(800, 600)
        self.terminal = QWidget(self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.terminal)
        self._start_process(
            'xterm',
            ['-into', str(self.terminal.winId()),
             '-e', 'tmux', 'new', '-s', 'my_session']
        )
        button = QPushButton('List files')
        layout.addWidget(button)
        button.clicked.connect(self._list_files)

    def _start_process(self, prog, args):
        child = QProcess()
        self._processes.append(child)
        child.start(prog, args)

    def _list_files(self):
        self._start_process(
            'tmux', ['send-keys', '-t', 'my_session:0', 'ls', 'Enter'])

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = embeddedTerminal()
    main.show()
    sys.exit(app.exec_())

Немного больше здесь: https://superuser.com/questions/492266/run-or-send-a-command-to-a-tmux-pane-in-a-running-tmux-session

Если кто-то еще столкнется с этим, внесите в него небольшие изменения, чтобы закрыть сеанс tmux, если он существует, поскольку предыдущий не закрыл его при выходе. Также настройте его для PySide2

Единственное, что ему сейчас нужно, это поддержка изменения размера.

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import psutil
import os
import platform
import sys
from pathlib import Path
from subprocess import call

from PySide2 import QtCore
from PySide2.QtCore import *
from PySide2.QtWidgets import QWidget, QVBoxLayout, QPushButton, QApplication

platform = platform.system()
print(str(platform))

term_dir = Path(os.path.abspath(os.path.dirname(__file__))) / 'terminus'

if platform == 'Windows':
    term_bin = str(term_dir) + '/' + str(platform.lower()) + '/' + 'terminus.exe'

elif platform == 'Linux':
    term_bin = str(term_dir) + '/' + str(platform.lower()) + '/' + 'terminus'

print(term_bin)


class embeddedTerminal(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        self._processes = []
        self.resize(800, 600)
        self.terminal = QWidget(self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.terminal)
        self._stop_process()
        self._start_process(
            'xterm',
            ['-into', str(self.terminal.winId()),
             '-e', 'tmux', 'new', '-s', 'my_session']
        )
        button = QPushButton('List files')
        layout.addWidget(button)
        button.clicked.connect(self._list_files)

    def _start_process(self, prog, args):
        child = QProcess()
        self._processes.append(child)
        child.start(prog, args)

    def _list_files(self):
        self._start_process(
            'tmux', ['send-keys', '-t', 'my_session:0', 'ls', 'Enter'])

    @classmethod
    def _stop_process(self):
        call(["tmux", "kill-session", "-t", "my_session"])


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = embeddedTerminal()
    main.show()
    sys.exit(app.exec_())

Другие вопросы по тегам