将xterm嵌入QWidget并与之通信
我想把一个 xterm
嵌入到一个 pyqt4
的小部件里,并且和它进行交流。特别是我希望能够向它打印信息,并在里面执行命令(这样在执行完命令后,它能像普通的命令行那样返回到正常的用户提示符)。请看下面这个简单的例子。我该怎么做才能让它工作呢?
#!/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 个回答
如果你想把一个 xterm
嵌入到你的某个窗口里,可以使用以下方法:
-into windowId 这个参数需要一个 X 窗口的标识符(一个十进制整数),这样 xterm 就会把它的顶层窗口嵌入到那个窗口中。这通常用来把 xterm 嵌入到其他应用程序里。
xterm
本身是和启动的 shell(比如 bash)进行沟通的。所以,你需要找到一种方法来和这个启动的 shell 进行交流。你可以通过 -Sccn
这个选项把打开的文件描述符传递给 xterm
:
这个选项允许 xterm 作为一个现有程序的输入和输出通道,有时在一些特殊应用中会用到。
所以,我觉得你需要创建一个 bash、zsh 或者你想发送命令的其他 shell 的实例。然后把那个子进程的 stdout/stderr 文件描述符连接到你的 xterm 实例,并把 stdin 连接到你的主程序,这样主程序就可以处理来自 xterm 的输入和你想发送给 bash 的命令(这样它们就会被执行并显示在 xterm 中)。
bash ----------------------> xterm
\--< your.py <----------/
urxvt
的手册页显示,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; # 清除执行时关闭
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/