PySide中的终端应用

3 投票
2 回答
4627 浏览
提问于 2025-04-17 19:13

我正在用PySide开发一个应用程序,我想添加一个像控制台/终端的界面,里面有一个提示符,可以输入命令。我该怎么做呢?我猜可以用QPlainTextEdit或者QTextEdit来显示输出,用QLineEdit来输入命令。有没有更好的方法呢?

2 个回答

1

我用自定义的 QPlainTextEdit 和 QLineEdit 做了这个。我还加了一个指示标签,在终端上显示“>>>”来表示用户输入。这部分还需要更多的工作。最好的方法是基于 QTextEdit 创建你自己的自定义控件,并且使用你自己的输入输出处理器。下面是我的执行方法的一个例子,其中 self.input 是 QLineEdit,self.view 是 QTextEdit。这个例子应该能让你大致明白。

import io, subprocess, shlex, code, rlcompleter, platform

def execute(self, currentText=None):
    """Execute runs the command given based on the console type.

    If the console type is "both" then execute will run python commands 
    unless the user give the input ::os::command or ("::(platform.syste())::command").
    Otherwise the console type will determine the what the input will execute with.

    Args:
        currentText(str): Text to execute. None will run the text from the QLineEdit self.input.
    """
    # Check for given text
    if currentText is None:
        currentText = self.input.text()
        self.input.clear()
        self.view.display(currentText, "input")
    else:
        cmd = re.search("^>>>", currentText) # search for start only 
        if cmd is None:
            currentText = ">>>" + currentText
        else:
            self.view.display(currentText, "input")
    # end

    # Variables
    self.completer.clear()
    cmdString = re.sub("^>>>", "", currentText)
    result = None
    displayType = "output"
    run, cmdString = self.getRunType(cmdString)

    try:
        # Check where the output is going
        sys.stdout = self.out = io.StringIO()
        sys.stderr = sys.stdout

        if run == "python": # Run python command
            result = self._runInterpreter(cmdString)
            displayType = "python"

        elif run == "os": # Run os command
            result = self._runSubprocess(cmdString)
            displayType = "os"
    except Exception as err:
        result = str(err)
        displayType = "Error"

        notFoundPython = "NameError:" in result and "is not defined" in result 
        notFoundWindows = "returned non-zero exit status" in result
        if notFoundPython or notFoundWindows:
            result = "Command not found"
    finally:
        sys.stdout = self.old_stdout
        sys.stderr = self.old_stdout

        self.display(result, displayType)
# end execute

def getRunType(self, cmdString):
    run = self._consoleType

    # Check the run type
    if self._consoleType == "both":
        if re.search("^::python::", cmdString) is not None:
            cmdString = re.sub("^::[a-z]*::", "", cmdString)
            run = "python"

        elif re.search("^(::os::|::"+platform.system()+"::)", cmdString) is not None:
            cmdString = re.sub("^::[a-z]*::", "", cmdString)
            run = "os"
        else:
            run = "python"
    # end

    return run, cmdString
# end getRunType

def _runInterpreter(self, cmdString, outIO=None, run=None):
    # Check for a proper console type
    if(self._consoleType != "both" and self._consoleType != "python"):
        return

    # Get the IO
    if outIO is None:
        outIO = sys.stdout

    # Run python command       

    self.interpreter.push(cmdString)

    # Check outIO
    result = "Unreadable buffer: Check python's sys.stdout"
    if isinstance(outIO, io.StringIO):
        result = outIO.getvalue()
    else:
        if outIO.readable():
            result = str(outIO.readlines())

    # Check for error
    if re.search("^Traceback", result) or re.search("[a-zA-z]*Error:", result):
        raise ValueError(result)

    return result
# end _runInterpreter

def _runSubprocess(self, cmdString, run=None):
    # Check for a proper console type
    if(self._consoleType != "both" and self._consoleType != "os"):
        return

    # Run OS command
    cmd = shlex.split(cmdString)
    result = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode("utf-8")

    # Check for error
    if re.search("^Traceback", result) or re.search("[a-zA-z]*Error:", result):
        raise ValueError(result)

    return result
# end _runSubprocess
1

你可以看看Spyder这个工具。它使用了PyQt(这两者很相似),并且有一个终端功能。我觉得你可以把他们的终端小部件导入过来,不过我自己还没试过。

https://code.google.com/p/spyderlib/

另外,它是我目前最喜欢的Python编辑器!

我花了不少时间寻找类似的工具,但一直没找到。祝你好运!

撰写回答