在 QPlainTextEdit 中使用 tqdm 显示终端输出
Display terminal output with tqdm in QPlainTextEdit
我正在尝试找到一种方法来获取 pyqt 应用程序中进度条的 result/evolution 以及其他打印件,例如在 QPlainTextEdit 小部件中。
我面临的问题是,进度条可以使用一些更高级的回车 return,或者更高级的光标定位,而这些大多不受 treams 支持。
我试过 io.StringIO
,但 \r
保持原样。
import io
from tqdm import tqdm
s = io.StringIO()
for i in tqdm(range(3), file=s):
sleep(.1)
输出:
s.getvalue()
Out[24]: '\n\r 0%| | 0/3 [00:00<?, ?it/s]\x1b[A\n\r 33%|###3 | 1/3 [00:00<00:00, 9.99it/s]\x1b[A\n\r 67%|######6 | 2/3 [00:00<00:00, 9.98it/s]\x1b[A\n\r100%|##########| 3/3 [00:00<00:00, 9.98it/s]\x1b[A\n\x1b[A'
转化为:
print(s.getvalue())
0%| | 0/3 [00:00<?, ?it/s]
33%|###3 | 1/3 [00:00<00:00, 9.99it/s]
67%|######6 | 2/3 [00:00<00:00, 9.98it/s]
100%|##########| 3/3 [00:00<00:00, 9.98it/s]
需要明确的是,在我的输出中,我不希望每个 tqdm 更新一行,而只是当前状态,因为它会打印在命令行上。
知道怎么做吗?
谢谢!
想法是如果添加了新文本,则删除上一行,但您还必须删除 \r
并验证它不是空文本。另外,对于接收tqdm
文本的对象,它必须只有write()
方法,所以实现一个自定义QPlainTextEdit
。使用 QMetaObject::invokeMethod()
使其成为线程安全的
import time
import threading
from tqdm import tqdm
from PyQt5 import QtCore, QtGui, QtWidgets
import lorem
class LogTextEdit(QtWidgets.QPlainTextEdit):
def write(self, message):
if not hasattr(self, "flag"):
self.flag = False
message = message.replace('\r', '').rstrip()
if message:
method = "replace_last_line" if self.flag else "appendPlainText"
QtCore.QMetaObject.invokeMethod(self,
method,
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(str, message))
self.flag = True
else:
self.flag = False
@QtCore.pyqtSlot(str)
def replace_last_line(self, text):
cursor = self.textCursor()
cursor.movePosition(QtGui.QTextCursor.End)
cursor.select(QtGui.QTextCursor.BlockUnderCursor)
cursor.removeSelectedText()
cursor.insertBlock()
self.setTextCursor(cursor)
self.insertPlainText(text)
def foo(w):
for i in tqdm(range(100), file=w):
time.sleep(0.1)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = LogTextEdit(readOnly=True)
w.appendPlainText(lorem.paragraph())
w.appendHtml("Welcome to Stack Overflow")
w.show()
threading.Thread(target=foo, args=(w,), daemon=True).start()
sys.exit(app.exec_())
我正在尝试找到一种方法来获取 pyqt 应用程序中进度条的 result/evolution 以及其他打印件,例如在 QPlainTextEdit 小部件中。
我面临的问题是,进度条可以使用一些更高级的回车 return,或者更高级的光标定位,而这些大多不受 treams 支持。
我试过 io.StringIO
,但 \r
保持原样。
import io
from tqdm import tqdm
s = io.StringIO()
for i in tqdm(range(3), file=s):
sleep(.1)
输出:
s.getvalue()
Out[24]: '\n\r 0%| | 0/3 [00:00<?, ?it/s]\x1b[A\n\r 33%|###3 | 1/3 [00:00<00:00, 9.99it/s]\x1b[A\n\r 67%|######6 | 2/3 [00:00<00:00, 9.98it/s]\x1b[A\n\r100%|##########| 3/3 [00:00<00:00, 9.98it/s]\x1b[A\n\x1b[A'
转化为:
print(s.getvalue())
0%| | 0/3 [00:00<?, ?it/s]
33%|###3 | 1/3 [00:00<00:00, 9.99it/s]
67%|######6 | 2/3 [00:00<00:00, 9.98it/s]
100%|##########| 3/3 [00:00<00:00, 9.98it/s]
需要明确的是,在我的输出中,我不希望每个 tqdm 更新一行,而只是当前状态,因为它会打印在命令行上。
知道怎么做吗? 谢谢!
想法是如果添加了新文本,则删除上一行,但您还必须删除 \r
并验证它不是空文本。另外,对于接收tqdm
文本的对象,它必须只有write()
方法,所以实现一个自定义QPlainTextEdit
。使用 QMetaObject::invokeMethod()
使其成为线程安全的
import time
import threading
from tqdm import tqdm
from PyQt5 import QtCore, QtGui, QtWidgets
import lorem
class LogTextEdit(QtWidgets.QPlainTextEdit):
def write(self, message):
if not hasattr(self, "flag"):
self.flag = False
message = message.replace('\r', '').rstrip()
if message:
method = "replace_last_line" if self.flag else "appendPlainText"
QtCore.QMetaObject.invokeMethod(self,
method,
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(str, message))
self.flag = True
else:
self.flag = False
@QtCore.pyqtSlot(str)
def replace_last_line(self, text):
cursor = self.textCursor()
cursor.movePosition(QtGui.QTextCursor.End)
cursor.select(QtGui.QTextCursor.BlockUnderCursor)
cursor.removeSelectedText()
cursor.insertBlock()
self.setTextCursor(cursor)
self.insertPlainText(text)
def foo(w):
for i in tqdm(range(100), file=w):
time.sleep(0.1)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = LogTextEdit(readOnly=True)
w.appendPlainText(lorem.paragraph())
w.appendHtml("Welcome to Stack Overflow")
w.show()
threading.Thread(target=foo, args=(w,), daemon=True).start()
sys.exit(app.exec_())