PyQt5 如何在阅读文本行时更新进度条?
PyQt5 How to make updating progress bar when line from text is reading?
我是 Python 和 PyQt 的初学者。我想做简单的 UI - 单击按钮打开文件对话框,接下来选择文本文件并将其逐行添加到列表中。这部分工作正常。当文件有大约 500k 行添加需要一些时间,所以决定做一个进度条。我正在搜索如何执行此操作,这是我的代码:
SIZE = 0
VALUE = 0
class External(QThread):
countChanged = pyqtSignal(int)
def run(self):
while VALUE <= SIZE:
counter = (VALUE*100/SIZE)
time.sleep(1)
self.countChanged.emit(int(counter))
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
\... some UI setup ...\
self.listView = QtWidgets.QListWidget()
self.pushButton = QtWidgets.QPushButton()
self.pushButton.clicked.connect(self.openFile)
self.progressBar = QtWidgets.QProgressBar()
def openFile(self):
global SIZE
global VALUE
openfile = QFileDialog.getOpenFileName(self.pushButton, "Open File", "", "TXT (*.txt)")
SIZE = os.stat(openfile[0]).st_size
if not openfile[0] == "":
with open(openfile[0], 'r') as f:
file_text = f.readlines()
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
for line in file_text:
self.listView.addItem(line)
VALUE = VALUE + sys.getsizeof(line)
def onCountChanged(self, counter):
self.progressBar.setValue(counter)
文本每次都会正确添加到列表中。进度条有时根本不加载,有时加载到百分之几(例如23%),但不显示实时进度,看起来是加载整个列表后添加的进度值。
1) 不确定我是否可以使用 getsizeof() 来检查已经处理了多少数据 - 我应该使用什么来代替?
2) 为什么我的进度条不能正常工作?代码应该是什么样的?
感谢您的关注。
首先,它不显示“实时进度”,因为你整整一秒钟都在睡觉,这不是很“实时”。
然后,你使用的是sys.getsizeof
,这是对象的大小,而不是线的大小,所以你必须使用len(line)
.
进度条结果不准确的原因在于 sleep
和 错误的尺寸计算:如果尺寸计算正确,它将永远不要退出 while 循环,但由于您实际上得到的 VALUE 将变得比 SIZE and 高得多,您每 1 秒才检查一次,循环退出太早.
最后,也许更好的方法是让线程负责加载(然后使用发出文本的信号填充列表);这将使它更准确,实际上实时。
class Loader(QtCore.QThread):
lineLoaded = QtCore.pyqtSignal(str)
def __init__(self, filePath):
super().__init__()
self.filePath = filePath
def run(self):
with open(self.filePath, 'r') as f:
for line in f.readlines():
self.lineLoaded.emit(line)
sleep(.001)
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
self.listView = QtWidgets.QListWidget()
layout.addWidget(self.listView)
self.pushButton = QtWidgets.QPushButton('Load file')
layout.addWidget(self.pushButton)
self.progressBar = QtWidgets.QProgressBar()
layout.addWidget(self.progressBar)
self.pushButton.clicked.connect(self.loadFile)
def loadFile(self):
openfile, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", "", "TXT (*.txt)")
if not openfile:
return
self.progressBar.setMaximum(QtCore.QFileInfo(openfile).size())
self.loader = Loader(openfile)
self.loader.lineLoaded.connect(self.loading)
self.loader.start()
def loading(self, line):
self.listView.addItem(line)
self.progressBar.setValue(self.progressBar.value() + len(line))
一个不相关的建议:您似乎在尝试模仿 pyuic
命令的输出,或者您刚刚编辑了该文件。这是 永远 不应该做的事情(出于各种原因,包括如果您需要更新 UI,您最终会遇到一个非常困难的重新整合过程具有 UI 修改的现有代码)。我建议你阅读更多关于正确 using Designer.
另外,避免像这样使用全局变量,这被认为是不好的做法,很容易导致问题和错误。
我是 Python 和 PyQt 的初学者。我想做简单的 UI - 单击按钮打开文件对话框,接下来选择文本文件并将其逐行添加到列表中。这部分工作正常。当文件有大约 500k 行添加需要一些时间,所以决定做一个进度条。我正在搜索如何执行此操作,这是我的代码:
SIZE = 0
VALUE = 0
class External(QThread):
countChanged = pyqtSignal(int)
def run(self):
while VALUE <= SIZE:
counter = (VALUE*100/SIZE)
time.sleep(1)
self.countChanged.emit(int(counter))
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
\... some UI setup ...\
self.listView = QtWidgets.QListWidget()
self.pushButton = QtWidgets.QPushButton()
self.pushButton.clicked.connect(self.openFile)
self.progressBar = QtWidgets.QProgressBar()
def openFile(self):
global SIZE
global VALUE
openfile = QFileDialog.getOpenFileName(self.pushButton, "Open File", "", "TXT (*.txt)")
SIZE = os.stat(openfile[0]).st_size
if not openfile[0] == "":
with open(openfile[0], 'r') as f:
file_text = f.readlines()
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
for line in file_text:
self.listView.addItem(line)
VALUE = VALUE + sys.getsizeof(line)
def onCountChanged(self, counter):
self.progressBar.setValue(counter)
文本每次都会正确添加到列表中。进度条有时根本不加载,有时加载到百分之几(例如23%),但不显示实时进度,看起来是加载整个列表后添加的进度值。
1) 不确定我是否可以使用 getsizeof() 来检查已经处理了多少数据 - 我应该使用什么来代替?
2) 为什么我的进度条不能正常工作?代码应该是什么样的?
感谢您的关注。
首先,它不显示“实时进度”,因为你整整一秒钟都在睡觉,这不是很“实时”。
然后,你使用的是sys.getsizeof
,这是对象的大小,而不是线的大小,所以你必须使用len(line)
.
进度条结果不准确的原因在于 sleep
和 错误的尺寸计算:如果尺寸计算正确,它将永远不要退出 while 循环,但由于您实际上得到的 VALUE 将变得比 SIZE and 高得多,您每 1 秒才检查一次,循环退出太早.
最后,也许更好的方法是让线程负责加载(然后使用发出文本的信号填充列表);这将使它更准确,实际上实时。
class Loader(QtCore.QThread):
lineLoaded = QtCore.pyqtSignal(str)
def __init__(self, filePath):
super().__init__()
self.filePath = filePath
def run(self):
with open(self.filePath, 'r') as f:
for line in f.readlines():
self.lineLoaded.emit(line)
sleep(.001)
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
self.listView = QtWidgets.QListWidget()
layout.addWidget(self.listView)
self.pushButton = QtWidgets.QPushButton('Load file')
layout.addWidget(self.pushButton)
self.progressBar = QtWidgets.QProgressBar()
layout.addWidget(self.progressBar)
self.pushButton.clicked.connect(self.loadFile)
def loadFile(self):
openfile, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", "", "TXT (*.txt)")
if not openfile:
return
self.progressBar.setMaximum(QtCore.QFileInfo(openfile).size())
self.loader = Loader(openfile)
self.loader.lineLoaded.connect(self.loading)
self.loader.start()
def loading(self, line):
self.listView.addItem(line)
self.progressBar.setValue(self.progressBar.value() + len(line))
一个不相关的建议:您似乎在尝试模仿 pyuic
命令的输出,或者您刚刚编辑了该文件。这是 永远 不应该做的事情(出于各种原因,包括如果您需要更新 UI,您最终会遇到一个非常困难的重新整合过程具有 UI 修改的现有代码)。我建议你阅读更多关于正确 using Designer.
另外,避免像这样使用全局变量,这被认为是不好的做法,很容易导致问题和错误。