0

コードサンプルは次のとおりです。

class RunGui (QtGui.QMainWindow)

    def __init__(self, parent=None):

        ...
        QtCore.Qobject.connect(self.ui.actionNew, QtCore.SIGNAL("triggered()"), self.new_select)
        ...


    def normal_output_written(self, qprocess):
        self.ui.text_edit.append("caught outputReady signal") #works
        self.ui.text_edit.append(str(qprocess.readAllStandardOutput())) # doesn't work


    def new_select(self):
        ...
        dialog_np = NewProjectDialog()
        dialog_np.exec_()
        if dialog_np.is_OK:
            section = dialog_np.get_section()
            project = dialog_np.get_project()
            ...
            np = NewProject()
            np.outputReady.connect(lambda: self.normal_output_written(np.qprocess))
            np.errorReady.connect(lambda: self.error_output_written(np.qprocess))
            np.inputNeeded.connect(lambda: self.input_from_line_edit(np.qprocess))
            np.params = partial(np.create_new_project, section, project, otherargs)
            np.start()

class NewProject(QtCore.QThread):

    outputReady = QtCore.pyqtSignal(object)
    errorReady = QtCore.pyqtSignal(object)
    inputNeeded = QtCore.pyqtSignal(object)
    params = None
    message = ""

    def __init__(self):
        super(NewProject, self).__init__()
        self.qprocess = QtCore.QProcess()
        self.qprocess.moveToThread(self)
        self._inputQueue = Queue()

    def run(self):
        self.params()

    def create_new_project(self, section, project, otherargs):
        ...
        # PyDev for some reason skips the breakpoints inside the thread
        self.qprocess.start(command)
        self.qprocess.waitForReadyRead()
        self.outputReady.emit(self.qprocess) # works - I'm getting signal in RunGui.normal_output_written()
        print(str(self.qprocess.readAllStandardOutput())) # prints empty line
        .... # other actions inside the method requiring "command" to finish properly.

アイデアは打ち負かされます-GUIにスクリプトを実行させ、プロセスと通信させます。この特定の例での課題は、コマンドがアプリを実行するときにQProcessでスクリプトが開始されることです。これには、途中でユーザー入力(確認)が必要です。したがって、スクリプトを開始し、すべての出力を取得して解析し、質問が出力に表示されるのを待ってから回答を返し、終了させて​​から、create_new_project(内の他のアクションを続行できるようにする必要があります。 )。

4

1 に答える 1

2

これで全体的な問題が解決するかどうかはわかりませんが、ここで確認できる設計上の問題がいくつかあります。

  1. qprocessの結果を使用してカスタムシグナルを発行するだけでなく、スレッド間でqprocessを渡します。
  2. おそらくインスタンス属性であるはずのクラスレベルの属性を使用しています

技術的には、QProcessをスレッドで実行し、ブロッキング呼び出しを積極的に使用しているため、QProcessも必要ありません。それは簡単にサブプロセスになる可能性があります。Popen...しかしとにかく、私は次のような変更を提案するかもしれません:

class RunGui (QtGui.QMainWindow)
    
    ...

    def normal_output_written(self, msg):
        self.ui.text_edit.append(msg) 

    def new_select(self):
        ...
            np = NewProject()
            np.outputReady.connect(self.normal_output_written)
            np.params = partial(np.create_new_project, section, project, otherargs)
            np.start()

class NewProject(QtCore.QThread):

    outputReady = QtCore.pyqtSignal(object)
    errorReady = QtCore.pyqtSignal(object)
    inputNeeded = QtCore.pyqtSignal(object)

    def __init__(self):
        super(NewProject, self).__init__()

        self._inputQueue = Queue()
        self.params = None

    def run(self):
        self.params()

    def create_new_project(self, section, project, otherargs):
        ...
        qprocess = QtCore.QProcess()
        qprocess.start(command)
        if not qprocess.waitForStarted():
            # handle a failed command here
            return

        if not qprocess.waitForReadyRead():
            # handle a timeout or error here
            return

        msg = str(self.qprocess.readAllStandardOutput())
        self.outputReady.emit(msg) 

QProcessを渡さないでください。データを出力するだけです。そして、threadsメソッド内から作成して、そのスレッドが自動的に所有するようにします。外部クラスは、実際にはそのQProcessオブジェクトに関する知識を持っていないはずです。操作中にのみ必要になるため、メンバー属性である必要はありません。

また、コマンドが正常に開始され、実行され、データが出力されていることを適切に確認してください。

アップデート

(コメントごとに)発生する可能性のあるいくつかの問題を明確にするために、定期的なユーザー入力を期待するプロセスとの対話型制御が必要な場合、QProcessが最良のオプションではない可能性があることを提案したいと思います。サブプロセスを実際に使用する方がはるかに簡単ですが、最初から最後まで出力を生成するだけのスクリプトを実行する場合は、findで機能するはずです。時間の経過とともにユーザー入力が必要なスクリプトの場合、最善の策はを使用することpexpectです。プロセスを生成し、入力の必要性を示すことがわかっているさまざまなパターンを監視できます。

foo.py

import time

i = raw_input("Please enter something: ")
print "Output:", i
time.sleep(.1)
print "Another line"
time.sleep(.1)
print "Done"

test.py

import pexpect
import time

child = pexpect.spawn("python foo.py")
child.setecho(False)

ret = -1
while ret < 0:
    time.sleep(.05)
    ret = child.expect("Please enter something: ")

child.sendline('FOO')
while True:
    line = child.readline()
    if not line:
        break
    print line.strip()

# Output: FOO
# Another line
# Done
于 2012-08-30T20:47:33.460 に答える