我试图找到一种方法,与其他打印件一起,在pyqt应用程序中(例如在QPlainTextEdit小部件中)获得进度条的结果/演变。
我面临的问题是,进度条可以使用一些更高级的回车符,甚至可以使用更高级的光标定位,而多数情况下,这些不支持用定标符。
我尝试过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更新一行,而只希望当前状态,因为它将被打印在命令行上。
任何想法o如何做到这一点? 谢谢!
答案 0 :(得分:2)
这个想法是,如果添加了新文本,则删除上一行,但是您还必须删除\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_())