2009-06-12 37 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()