我想使用wxPython创建一个弹出窗口,其作用类似于bash shell。我不想要一个终端模拟器,我不需要作业控制,我只想要一个基于bash过程的REPL(读取,评估,打印循环)。
使用wxPython有一种简单的方法吗?我知道我作为一名tcl / tk程序员的基本概念,但我的wxPython fu很弱,如果我不需要,我不想重新发明轮子。我已经阅读了一些关于py.shell的内容。 Shell,但看起来它创建了一个python shell,我想要一个运行bash命令。
答案 0 :(得分:6)
这里是另一个尝试,它在一个单独的线程中读取所有输出和错误,并通过Queue进行通信。 我知道这不是完美的(例如,延迟输出的命令将不起作用,并且输出将进入下一个提交,例如tryr sleep 1; date)并且复制整个bash不是微不足道的但是对于我测试的几个命令它似乎工作正常
关于wx.py.shell的API,我刚刚实现了Shell类为Interpreter调用的那些方法,如果你通过Shell的源代码,你就会理解。 基本上
getAutoCompleteList返回列表 命令匹配给定文本
getCallTip“显示参数规范和 弹出窗口中的docstring。因此对于 bash我们可能会显示手册页:)
这是源代码
import threading
import Queue
import time
import wx
import wx.py
from subprocess import Popen, PIPE
class BashProcessThread(threading.Thread):
def __init__(self, readlineFunc):
threading.Thread.__init__(self)
self.readlineFunc = readlineFunc
self.outputQueue = Queue.Queue()
self.setDaemon(True)
def run(self):
while True:
line = self.readlineFunc()
self.outputQueue.put(line)
def getOutput(self):
""" called from other thread """
lines = []
while True:
try:
line = self.outputQueue.get_nowait()
lines.append(line)
except Queue.Empty:
break
return ''.join(lines)
class MyInterpretor(object):
def __init__(self, locals, rawin, stdin, stdout, stderr):
self.introText = "Welcome to stackoverflow bash shell"
self.locals = locals
self.revision = 1.0
self.rawin = rawin
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.more = False
# bash process
self.bp = Popen('bash', shell=False, stdout=PIPE, stdin=PIPE, stderr=PIPE)
# start output grab thread
self.outputThread = BashProcessThread(self.bp.stdout.readline)
self.outputThread.start()
# start err grab thread
self.errorThread = BashProcessThread(self.bp.stderr.readline)
self.errorThread.start()
def getAutoCompleteKeys(self):
return [ord('\t')]
def getAutoCompleteList(self, *args, **kwargs):
return []
def getCallTip(self, command):
return ""
def push(self, command):
command = command.strip()
if not command: return
self.bp.stdin.write(command+"\n")
# wait a bit
time.sleep(.1)
# print output
self.stdout.write(self.outputThread.getOutput())
# print error
self.stderr.write(self.errorThread.getOutput())
app = wx.PySimpleApp()
frame = wx.py.shell.ShellFrame(InterpClass=MyInterpretor)
frame.Show()
app.SetTopWindow(frame)
app.MainLoop()
答案 1 :(得分:1)
我找到了解决问题的方法。有趣的是它之前从未在谷歌搜索中出现过。它不是生产就绪代码,但最终我正在寻找 - 一种在wxPython窗口中运行bash shell的方法。
http://sivachandran.blogspot.com/2008/04/termemulator-10-released.html
答案 2 :(得分:0)
我搜索过但似乎没有任何针对wxPython的退出bash shell 虽然wx.py模块有Shell模块,用于python解释器 好的是你可以将自己的解释器传递给它,所以我带来了非常简单的bash解释器。 示例当前只从bash stdout读取一行,否则会卡住, 在实际代码中,您必须在线程中读取输出或使用选择
import wx
import wx.py
from subprocess import Popen, PIPE
class MyInterpretor(object):
def __init__(self, locals, rawin, stdin, stdout, stderr):
self.introText = "Welcome to stackoverflow bash shell"
self.locals = locals
self.revision = 1.0
self.rawin = rawin
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
#
self.more = False
# bash process
self.bp = Popen('bash', shell=False, stdout=PIPE, stdin=PIPE, stderr=PIPE)
def getAutoCompleteKeys(self):
return [ord('\t')]
def getAutoCompleteList(self, *args, **kwargs):
return []
def getCallTip(self, command):
return ""
def push(self, command):
command = command.strip()
if not command: return
self.bp.stdin.write(command+"\n")
self.stdout.write(self.bp.stdout.readline())
app = wx.PySimpleApp()
frame = wx.py.shell.ShellFrame(InterpClass=MyInterpretor)
frame.Show()
app.SetTopWindow(frame)
app.MainLoop()
答案 3 :(得分:0)
去看看我能想出什么。
但如果你改变主意并决定改用pygtk,那么它就是:
修改强>
我开始使用文本控件小部件创建一个穷人的终端版本。 我停止了因为存在无法修复的缺陷,例如当你使用sudo命令时。
import wx
import subprocess
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MyFrame.__init__
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.prompt = "user@stackOvervlow:~ "
self.textctrl = wx.TextCtrl(self, -1, '', style=wx.TE_PROCESS_ENTER|wx.TE_MULTILINE)
self.default_txt = self.textctrl.GetDefaultStyle()
self.textctrl.AppendText(self.prompt)
self.__set_properties()
self.__do_layout()
self.__bind_events()
def __bind_events(self):
self.Bind(wx.EVT_TEXT_ENTER, self.__enter)
def __enter(self, e):
self.value = (self.textctrl.GetValue())
self.eval_last_line()
e.Skip()
def __set_properties(self):
self.SetTitle("Poor Man's Terminal")
self.SetSize((800, 600))
self.textctrl.SetFocus()
def __do_layout(self):
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_1.Add(self.textctrl, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.Layout()
def eval_last_line(self):
nl = self.textctrl.GetNumberOfLines()
ln = self.textctrl.GetLineText(nl-1)
ln = ln[len(self.prompt):]
args = ln.split(" ")
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
retvalue = proc.communicate()[0]
c = wx.Colour(239, 177, 177)
tc = wx.TextAttr(c)
self.textctrl.SetDefaultStyle(tc)
self.textctrl.AppendText(retvalue)
self.textctrl.SetDefaultStyle(self.default_txt)
self.textctrl.AppendText(self.prompt)
self.textctrl.SetInsertionPoint(GetLastPosition() - 1)
if __name__ == "__main__":
app = wx.PySimpleApp(0)
wx.InitAllImageHandlers()
frame_1 = MyFrame(None, -1, "")
app.SetTopWindow(frame_1)
frame_1.Show()
app.MainLoop()
如果真的想要,可以解决这个问题。