【问题标题】:PyQt5 pass command to embedded terminal 'urxvt' or 'xterm'PyQt5 将命令传递给嵌入式终端“urxvt”或“xterm”
【发布时间】:2021-01-08 02:13:52
【问题描述】:

我已经完成了 PyQt5 应用程序的嵌入式终端,请关注此answer

现在我想使用按钮向这个嵌入式终端发送命令,类似于here

例如:

Button_1 send "ifconfig", 
Button_2 send "ping 127.0.0.1". 

我的代码:

import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QPushButton


class EmbTerminal(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(EmbTerminal, self).__init__(parent)
        self.process = QtCore.QProcess(self)
        self.terminal = QtWidgets.QWidget(self)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.terminal)
        # Works also with urxvt:
        # self.process.start('urxvt',['-embed', str(int(self.winId()))])
        self.process.start('xterm',['-into', str(int(self.winId()))])
        # self.setFixedSize(640, 480)

        button1 = QPushButton('ifconfig')
        layout.addWidget(button1)
        button1.clicked.connect(self.button_1_clicked)

        button2 = QPushButton('ping 127.0.0.1')
        layout.addWidget(button2)
        button2.clicked.connect(self.button_2_clicked)

    def button_1_clicked(self):
        print('send \"ifconfig\" to embedded termial')

    def button_2_clicked(self):
        print('send \"ping 127.0.0.1\" to embedded termial')

class mainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(mainWindow, self).__init__(parent)

        central_widget = QtWidgets.QWidget()
        lay = QtWidgets.QVBoxLayout(central_widget)
        self.setCentralWidget(central_widget)

        tab_widget = QtWidgets.QTabWidget()
        lay.addWidget(tab_widget)

        tab_widget.addTab(EmbTerminal(), "EmbTerminal")
        tab_widget.addTab(QtWidgets.QTextEdit(), "QTextEdit")
        tab_widget.addTab(QtWidgets.QMdiArea(), "QMdiArea")


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

我该怎么做?

我已经尝试过其他answer(将另一个应用程序附加到 PyQt5 窗口)和answer(将命令传递给 QProcess C++ 而不是 Python)

【问题讨论】:

    标签: python pyqt5 xterm urxvt


    【解决方案1】:

    将上述接受的答案与answer 结合起来后,我已经完成了我的要求。

    这是组合代码,在 Python2-Qt5 上运行

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets
    import gi
    import uuid
    gi.require_version('Wnck', '3.0')
    from gi.repository import Wnck, Gdk
    import time
    
    class Container(QtWidgets.QTabWidget):
        def __init__(self):
            QtWidgets.QTabWidget.__init__(self)
            self.embed('xterm')
    
        def embed(self, command, *args):
            self.name_session = uuid.uuid4().hex
            proc = QtCore.QProcess()
            proc.setProgram(command)
            proc.setArguments(args)
    
            started, procId = QtCore.QProcess.startDetached(
                "xterm", ["-e", "tmux", "new", "-s", self.name_session], "."
            )
            if not started:
                QtWidgets.QMessageBox.critical(self, 'Command "{}" not started!'.format(command), "Eh")
                return
            attempts = 0
            while attempts < 10:
                screen = Wnck.Screen.get_default()
                screen.force_update()
                # do a bit of sleep, else window is not really found
                time.sleep(0.1)
                # this is required to ensure that newly mapped window get listed.
                while Gdk.events_pending():
                    Gdk.event_get()
                for w in screen.get_windows():
                    print(attempts, w.get_pid(), procId, w.get_pid() == procId)
                    if w.get_pid() == procId:
                        self.window = QtGui.QWindow.fromWinId(w.get_xid())
                        proc.setParent(self)
                        win32w = QtGui.QWindow.fromWinId(w.get_xid())
                        win32w.setFlags(QtCore.Qt.FramelessWindowHint)
                        widg = QtWidgets.QWidget.createWindowContainer(win32w)
    
                        self.addTab(widg, command)
                        self.resize(500, 400) # set initial size of window
                        return
                attempts += 1
            QtWidgets.QMessageBox.critical(self, 'Window not found', 'Process started but window not found')
    
        def stop(self):
            QtCore.QProcess.execute("tmux", ["kill-session", "-t", self.name_session])
    
        def send_command(self, command):
            QtCore.QProcess.execute(
                "tmux", ["send-keys", "-t", self.name_session, command, "Enter"]
            )
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
    
            self.ifconfig_btn = QtWidgets.QPushButton("ifconfig")
            self.ping_btn = QtWidgets.QPushButton("ping")
            self.terminal = Container()
    
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
    
            lay = QtWidgets.QGridLayout(central_widget)
            lay.addWidget(self.ifconfig_btn, 0, 0)
            lay.addWidget(self.ping_btn, 0, 1)
            lay.addWidget(self.terminal, 1, 0, 1, 2)
    
            self.resize(640, 480)
    
            self.ifconfig_btn.clicked.connect(self.launch_ifconfig)
            self.ping_btn.clicked.connect(self.launch_ping)
    
        def launch_ifconfig(self):
            self.terminal.send_command("ifconfig")
    
        def launch_ping(self):
            self.terminal.send_command("ping 8.8.8.8")
    
        def closeEvent(self, event):
            self.terminal.stop()
            super().closeEvent(event)
    
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
    

    【讨论】:

      【解决方案2】:

      一种可能的解决方案是使用tmux 作为中介来发送命令:

      import sys
      import time
      import uuid
      
      from PyQt5 import QtCore, QtGui, QtWidgets
      
      import gi
      
      gi.require_version("Wnck", "3.0")
      from gi.repository import Wnck, Gdk
      
      
      class TerminalContainer(QtWidgets.QTabWidget):
          def __init__(self, parent=None):
              super().__init__(parent)
              lay = QtWidgets.QVBoxLayout(self)
              lay.setContentsMargins(0, 0, 0, 0)
              self.name_session = uuid.uuid4().hex
      
          def start(self):
              started, procId = QtCore.QProcess.startDetached(
                  "xterm", ["-e", "tmux", "new", "-s", self.name_session], "."
              )
              if not started:
                  QtWidgets.QMessageBox.critical(
                      self, 'Command "{}" not started!'.format(command), "Eh"
                  )
                  return
              attempts = 0
              while attempts < 10:
                  screen = Wnck.Screen.get_default()
                  screen.force_update()
                  time.sleep(0.1)
                  while Gdk.events_pending():
                      Gdk.event_get()
                  for w in screen.get_windows():
                      print(attempts, w.get_pid(), procId, w.get_pid() == procId)
                      if w.get_pid() == procId:
                          win32w = QtGui.QWindow.fromWinId(w.get_xid())
                          widg = QtWidgets.QWidget.createWindowContainer(win32w)
                          self.layout().addWidget(widg)
                          self.resize(500, 400)
                          return
                  attempts += 1
              QtWidgets.QMessageBox.critical(
                  self, "Window not found", "Process started but window not found"
              )
      
          def stop(self):
              QtCore.QProcess.execute("tmux", ["kill-session", "-t", self.name_session])
      
          def send_command(self, command):
              QtCore.QProcess.execute(
                  "tmux", ["send-keys", "-t", self.name_session, command, "Enter"]
              )
      
      
      class MainWindow(QtWidgets.QMainWindow):
          def __init__(self, parent=None):
              super().__init__(parent)
      
              self.ifconfig_btn = QtWidgets.QPushButton("ifconfig")
              self.ping_btn = QtWidgets.QPushButton("ping")
              self.terminal = TerminalContainer()
      
              central_widget = QtWidgets.QWidget()
              self.setCentralWidget(central_widget)
      
              lay = QtWidgets.QGridLayout(central_widget)
              lay.addWidget(self.ifconfig_btn, 0, 0)
              lay.addWidget(self.ping_btn, 0, 1)
              lay.addWidget(self.terminal, 1, 0, 1, 2)
      
              self.terminal.start()
      
              self.resize(640, 480)
      
              self.ifconfig_btn.clicked.connect(self.launch_ifconfig)
              self.ping_btn.clicked.connect(self.launch_ping)
      
          def launch_ifconfig(self):
              self.terminal.send_command("ifconfig")
      
          def launch_ping(self):
              self.terminal.send_command("ping 8.8.8.8")
      
          def closeEvent(self, event):
              self.terminal.stop()
              super().closeEvent(event)
      
      
      if __name__ == "__main__":
          app = QtWidgets.QApplication(sys.argv)
          main = MainWindow()
          main.show()
          sys.exit(app.exec_())
      

      【讨论】:

      • 谢谢!发送命令完美运行。但“xterm”不能对接“MainWindow”。出现2个窗口
      猜你喜欢
      • 1970-01-01
      • 2019-01-29
      • 2012-05-01
      • 2016-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-11
      相关资源
      最近更新 更多