2009-06-12 36 views
7

我想用wxPython创建一个弹出窗口,它的作用类似于bash shell。我不想要终端模拟器,我不需要作业控制,我只想要基于bash过程的REPL(读取,评估,打印循环)。wxPython:如何创建一个bash shell窗口?

是否有一个简单的方法来做到这一点与wxPython的?我知道我作为一名tcl/tk程序员的基本概念,但是我的wxPython fu功能很弱,如果不需要,我不想重新发明轮子。我读了一些关于py.shell的内容。壳,但看起来像它创建一个Python shell,我想要一个运行bash命令。

+0

什么是“REPL”? – 2009-06-15 19:58:42

+1

A-Read-Eval-Print-Loop – 2009-06-15 21:57:52

回答

0

我搜查,但似乎并没有成为wxPython的 任何退出的bash shell虽然wx.py模块外壳模块,这是蟒蛇解释器 好处是你可以通过你自己的解释器吧,所以我有来与非常简单的bash解释器。 例如目前读取bash的标准输出只有一条线,否则会在真正的代码,你必须在线程读取输出或使用卡住, 选择

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() 
+0

为什么-1?请放下评论后尽快发表评论,所以我有机会改善自己,我看不到投票的理由吗? – 2009-06-16 11:37:52

+0

我降低了投票权,因为这不是工作代码。鉴于有一个奖金,这里的酒吧比平常高一点。 好吧,代码运行时没有错误,但它不是可以原样使用的东西,也不是当它在每个命令之后只读取一行输出时。我很欣赏指向wx.py.Shell小部件的指针,以及如何创建一个特殊的解释器,但这还不足以让IMO获得赏金。 – 2009-06-16 13:53:26

0

将看看我能想出。

但是,如果你改变了主意,决定使用PyGTK的代替,那就是:

enjoy!!

编辑

我开始使用的文本进行一个穷人版的终端控件。 我停止了,因为存在无法修复的缺陷,例如当您使用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 = "[email protected]:~ " 
     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() 

如果真的想要,这可以被处理。

6

确定这里是另一种尝试,其内容为所有的输出和错误也是如此,在一个单独的线程,并通过队列进行通信。 我知道这是不完美的(例如,具有延迟输出命令将不起作用,在输出将进入下一commnd例如tryr睡眠1;日期),并复制整个庆典不平凡的,但对于我测试几个命令它似乎做工精细

关于wx.py.shell我只是实现那些贝壳类被要求解释,如果你去通壳牌的源代码,你会明白的方法API。 基本上

  • 推是其中用户输入的命令被发送给解释
  • getAutoCompleteKeys返回键 其中用户可以为用户自动 完成命令例如的 命令配合的突出重点
  • getAutoCompleteList返回列表中给出的文本

  • getCallTip“显示参数规格, 文档字符串中的弹出窗口。所以 庆典,我们可能会显示手册页:)

这里是源代码

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()