Ui和逻辑分离尝试0

Posted by kifish on April 23, 2018

可以先学习这篇: -https://nikolak.com/pyqt-qt-designer-getting-started/

class Backend(QtCore.QThread):
    update_output = QtCore.pyqtSignal(str)
    def run(self):
        test()
        res = sys.stdout
        self.update_output.emit(str(res))

def test():
    x = 1
    while x < 10:
        x += 1
        print(x)
        time.sleep(1)

这样只能等test()执行完才能获得输出

from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow,QLineEdit,QDialog,QTextBrowser,QVBoxLayout,QHBoxLayout

import datetime
import time
import sys
import subprocess
import shlex

class Backend(QtCore.QThread):
    update_output = QtCore.pyqtSignal(str)

    def run(self):
        shell_cmd = 'python main.py'
        cmd = shlex.split(shell_cmd)
        p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE)
        while p.poll() is None:
            line = p.stdout.readline()
            print('get '+line.decode())
            self.update_output.emit(str(line.decode()))




class Window(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.resize(400, 100)
        hbox = QHBoxLayout()
        vbox = QVBoxLayout()

        self.input = QTextBrowser(self)
        self.input.sizeHint()

        hbox.addWidget(self.input)
        self.setLayout(hbox)
    def handleDisplay(self, data):
        self.input.append(data)


if __name__ == '__main__':

    app = QApplication(sys.argv)
    b = Backend()
    w = Window()
    b.update_output.connect(w.handleDisplay)
    b.start()
    w.show()
    app.exec_()


这样的话逻辑和ui完全分离,但是似乎没法用按钮来启动。

gui.py


from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow,QLineEdit,QDialog,QTextBrowser,QVBoxLayout,QHBoxLayout,QPushButton

import datetime
import time
import sys
import subprocess
import shlex

class Backend(QtCore.QThread):
    update_output = QtCore.pyqtSignal(str)

    def run(self):
        shell_cmd = 'python main.py'
        cmd = shlex.split(shell_cmd)
        p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE)
        while p.poll() is None:
            line = p.stdout.readline()
            print('get '+line.decode())
            self.update_output.emit(str(line.decode()))




class Window(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.resize(800, 500)

        startButton = QPushButton("Start")
        cancelButton = QPushButton("Cancel")
        startButton.clicked.connect(self.handleStart)

        hbox = QHBoxLayout()
        vbox = QVBoxLayout()

        self.input = QTextBrowser(self)
        self.input.sizeHint()

        vbox.addWidget(startButton)
        vbox.addWidget(cancelButton)

        hbox.addWidget(self.input)

        total_hbox = QHBoxLayout()
        #total_hbox.addStretch(1)  #这排版不对
        total_hbox.addLayout(vbox)
        total_hbox.addLayout(hbox)
        self.setLayout(total_hbox)

    def handleDisplay(self, data):
        self.input.append(data)

    def handleStart(self):
        b = Backend()
        b.update_output.connect(w.handleDisplay)
        b.start()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    w = Window()
    w.show()
    app.exec_()

python gui.py
QThread: Destroyed while thread is still running
[1] 65989 segmentation fault python gui.py

分析: 执行handleStart函数,产生b进程,b进程产生子进程,函数返回试图销毁b实例,导致报错。

override del

class Backend(QtCore.QThread):
    update_output = QtCore.pyqtSignal(str)
    def __del__(self):
        print("Don't dellllllllllllllllllllllllllllllllllllll")
        self.wait()

    def run(self):
        shell_cmd = 'python main.py'
        cmd = shlex.split(shell_cmd)
        p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE)
        while p.poll() is None:
            line = p.stdout.readline()
            print('get '+line.decode())  #for debug
            self.update_output.emit(str(line.decode()))

如果override del ,那么会等到b进程及其子进程全部结束后 GUI才有输出。

解决方案:

        self.threads = []              # this will keep a reference to threads
        thread = MyThread(self)    # create a thread
        thread.trigger.connect(self.update_text)  # connect to it's signal
        thread.start()             # start the thread
        self.threads.append(thread) # keep a reference