今天学习opencv和pyqt的结合,从国外一篇博客看到可以使用print函数,直接在pyqt控件上输出。觉得很有意思,仔细研究了一下原理,发现其实也不是很难。
思想
当我们调用print函数,比如
print("hello")
其实调用了
sys.stdout.write()
sys.stdout.flush()
因此,希望print输出到一个控件上,在上面两个函数上进行重写即可。
例1
我们直接改写sys.stdout
下的write和flush函数即可
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QWidget
class MyWindow(QMainWindow):
def __init__(self, parent=None):
# ------------------------------
# Set the UI
QMainWindow.__init__(self, parent)
self.central = QWidget(self)
self.textbox = QTextEdit(self.central)
self.textbox.setMinimumSize(300, 100)
self.setCentralWidget(self.central)
# ------------------------------
# Set print
# 连接sys.stdout
sys.stdout = self
print("hello")
print("world", end="")
print(",every body")
# ------------------------------
# sys.stdout模块下的write 和 flush在此重写
def write(self, text):
self.textbox.insertPlainText(text)
def flush(self):
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec_())
# EOF
总结
直接改写子类中的write和flush函数,easy!
例2 使用信号与槽
使用信号机制,信号与槽的初高级玩法网上有不少介绍 ,使用这种方法,不用去担心它们在哪个线程。
import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QWidget
from PyQt5.QtGui import QTextCursor
class MyWindow(QMainWindow):
# 信号必须在此声明
# 1.声明一个带str的信号
text_update = pyqtSignal(str)
# Create main window
def __init__(self, parent=None):
# ------------------------------
# Set UI
QMainWindow.__init__(self, parent)
self.central = QWidget(self)
self.textbox = QTextEdit(self.central)
self.textbox.setMinimumSize(300, 100)
self.setCentralWidget(self.central)
# ------------------------------
# 2.连接信号的槽函数,信号若发出,运行槽函数
self.text_update.connect(self.append_text)
# 3.连接sys.stdout
sys.stdout = self
print("hello")
# ------------------------------
# 4 sys.stdout模块下的write 和 flush在此重写
# 用信号机制触发函数,操作控件
def write(self, text):
self.text_update.emit(str(text))
def flush(self):
pass
# ------------------------------
# 5.槽函数
def append_text(self, text):
cur = self.textbox.textCursor() # Move cursor to end of text
cur.movePosition(QTextCursor.End)
s = str(text)
while s:
head, sep, s = s.partition("\n") # Split line at LF
cur.insertText(head) # Insert text at cursor
if sep: # New line if LF
cur.insertBlock()
self.textbox.setTextCursor(cur) # Update visible cursor
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec_())
# EOF
可见,print函数调用经过以下流程
print --> sys.stdout.write --> text_update.emit(text) --> append_text(text)
总结
例2步骤稍显麻烦,其实分两路:
一路是信号触发机制,信号触发时,调用控件修改函数
另一路是如何调整信号呢?在 sys.stdout的write和flush函数
参考
https://iosoft.blog/2019/07/31/rpi-camera-display-pyqt-opencv/