将xterm嵌入QWidget并与之通信

3

我想将一个xterm嵌入到一个pyqt4小部件中,并与之通信。特别是,我希望能够向其打印并在其中执行命令(使其在执行命令后返回到正常用户提示符,就像普通的shell一样)。考虑以下最简示例。如何让它工作?

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

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


class embedxterm(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        self.setMinimumWidth(900)
        self.setMinimumHeight(400)
        self.process = QProcess(self)

        self.terminal = QWidget(self)
        self.terminal.setMinimumHeight(300)

        self.cmd1 = QPushButton('Command1',self)
        self.cmd2 = QPushButton('Command2',self)
        self.hello = QPushButton('Print Hello World',self)

        layout = QVBoxLayout(self)

        layoutH = QHBoxLayout(self)

        layoutH.addWidget(self.cmd1)
        layoutH.addWidget(self.cmd2)
        layoutH.addWidget(self.hello)


        layout.addLayout(layoutH)
        layout.addWidget(self.terminal)


        self.process.start(
            'xterm',['-into', str(self.terminal.winId())])

        self.cmd1.clicked.connect(self.Ccmd1)
        self.cmd2.clicked.connect(self.Ccmd2)
        self.hello.clicked.connect(self.Chello)

    def Ccmd1(self):
        self.process.write('ls -l')
        # Should execute ls -l on this terminal

    def Ccmd2(self):
        self.process.write('ping www.google.com')
        # should execute ping www.google.com on this terminal

    def Chello(self):
        self.process.write('Hello World')
        # should just print "Hello World" on this terminal

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = embedxterm()
    main.show()
    sys.exit(app.exec_())
1个回答

4
要将xterm嵌入到您的窗口中,您应该使用以下命令:

-into windowId 给定X窗口标识符(十进制整数),xterm将重新父级其顶级shell小部件到该窗口。这用于在其他应用程序中嵌入xterm。

xterm本身与启动的shell(bash等)通信。因此,您必须找到一种与已启动shell通信的方法。您可以通过-Sccn标志将打开的文件描述符传递给xterm

此选项允许将xterm用作现有程序的输入和输出通道,并且有时用于专业应用程序

因此,我认为您需要创建自己的bash、zsh实例,无论您想要发送命令到哪个终端。然后将该子进程的标准输出/标准错误FD连接到xterm的实例,并将标准输入连接到主程序,然后复用来自xterm的输入和您要发送到bash的命令(因此它们将被执行并显示在xterm中)。
bash ----------------------> xterm
    \--< your.py <----------/
urxvt的man手册显示,urxvt有一些类似的开关:

-embed windowid
告诉urxvt将它的窗口嵌入到一个已经存在的窗口中,这使得应用程序可以轻松地嵌入终端。 [ ... ] 这里是一个简短的Gtk2-perl代码片段,说明了如何使用此选项(更长的示例在doc/embed中):

my $rxvt = new Gtk2::Socket;
$rxvt->signal_connect_after (realize => sub { my $xid = $_[0]->window->get_xid;
system "urxvt -embed $xid &";
});

-pty-fd file descriptor
告诉urxvt不要执行任何命令或创建新的pty/tty对,而是使用给定的文件描述符作为tty主设备。如果你想以通用终端仿真器的方式驱动urxvt而不必在其中运行程序,则这很有用。

这是一个perl示例,说明了如何使用此选项(更长的示例在doc/pty-fd中):

use IO::Pty;
use Fcntl;

my $pty = new IO::Pty;
fcntl $pty, F_SETFD, 0; # clear close-on-exec
system "urxvt -pty-fd " . (fileno $pty) . "&";
close $pty;

# 现在与rxvt通信
my $slave = $pty->slave;
while () { print $slave "got \n" }

要从python中打开PTY,pty模块看起来很有前途:http://docs.python.org/2/library/pty.html

有趣的阅读:http://sqizit.bartletts.id.au/2011/02/14/pseudo-terminals-in-python/


谢谢,但我没有把这些部分组合起来。也许有人可以针对我的最小示例,或者至少针对pyqt4给出更多细节。 - student
1
你不明白我回答的哪一部分? - akira
所以实际上你并没有理解我关于整个事情如何工作的写法。在xterm中获取正在运行的进程是“不可能”的。这就是为什么你必须提供文件描述符,xterm才能与之通信。xterm只是一个窗口,用于显示实际执行某些操作的进程中正在发生的事情。而且我不会使用qt-api来处理子进程,而是使用本地Python API来处理子进程。 - akira
是的,我不明白如何具体实现这个。你能否提供一个在Python中工作的具体示例? - student
2
不行,因为我没有时间替你完成这项工作。我仍然感觉你没有理解我所阐述的概念。 - akira
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接