可以先学习这篇: -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