我对Q标签中的实时更新有疑问,因为当我点击“开始”按钮时,屏幕会在执行计算时保持静态几秒钟,但我需要的是在QLabel在模拟前进时显示状态消息。我已尝试使用线程,但我不太了解它,因为它没有成功,如果有人可以帮助我,我会很感激,因为我没有处理Pyqt5中的线程问题。 (我不明白) 非常感谢你
我附上了界面的代码和图片:
接口
执行前:
执行期间:
执行后:
Codigo
import sys
from PyQt5.QtWidgets import QStyleFactory,QApplication, QMainWindow,QFileDialog
from PyQt5.uic import loadUi
from PyQt5.QtGui import QTextCursor
from PyQt5.QtCore import *
import random
import time
import pandas as pd
parametros = [['Area', 0, 5]]
class simulacion(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
loadUi('simulacion.ui', self)
self.setStyle(QStyleFactory.create('Fusion'))
self.numsim = 10000000
self.pushButton.clicked.connect(self.calibracion)
self.pushButton_2.clicked.connect(self.save)
def cerrar(self):
self.close()
def calibracion(self):
self.montecarlo(self.numsim)
def generar_aleatorio(self):
aleatorio = []
for i in range(len(parametros)):
aleatorio.append(random.uniform(parametros[i][1],parametros[i][2]))
return aleatorio
def area(self,x1):
area = 3.1416 * x1**2
return area
def estado(self,starttime,last_print,contador, n, area):
global ult_print
acttime = time.time()
if acttime - last_print >= 2:
avg_time_per_run = (acttime - starttime) / (contador + 1)
timestr = time.strftime("%H:%M:%S", time.gmtime(round(avg_time_per_run * (n - (contador + 1)))))
text = ('Simulacion %i de %i - Tiempo estimado restante: %s\n' % (contador, n,timestr)+'Area = %5.3f' % (area)+'\n\n')
self.textEdit.moveCursor(QTextCursor.End)
self.textEdit.insertPlainText(text)
self.textEdit.moveCursor(QTextCursor.End)
ult_print = time.time()
return text
def montecarlo(self,n):
QApplication.processEvents()
global ult_print
text='Iniciando iteraciones con {} repeticiones...\n\n'.format(n)
self.textEdit.setText(text)
self.textEdit.moveCursor(QTextCursor.End)
ult_print = time.time()
starttime = time.time()
contador = 0
self.data=[]
self.num_sim=[]
QApplication.setOverrideCursor(Qt.WaitCursor)
while contador < n:
contador +=1
#Generar el numero aleatorio
z = self.generar_aleatorio()
#Simulacion del modelo con el numero aleatorio
y = self.area(z[0])
#Calculo de la funcion objetivo
self.estado(starttime,ult_print,contador,n,y)
QApplication.setOverrideCursor(Qt.CustomCursor)
def save(self):
file,_=QFileDialog.getSaveFileName(self,'Guardar Archivo de Simulación','','(*.csv)')
if file:
columns= []
for valor in self.num_sim:
columns.append('Simulación '+str(valor))
#print(columns)
df = pd.DataFrame(self.data,index=columns)
a = df.transpose()
a.to_csv(file,sep=';',index=False,encoding='utf-8')
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = simulacion()
widget.show()
sys.exit(app.exec_())
这里我展示了simulacion.ui
的单独调用代码Codigo
import sys
from PyQt5.QtWidgets import QStyleFactory,QApplication,
QMainWindow,QFileDialog
from PyQt5.uic import loadUi
from PyQt5.QtGui import QTextCursor
from PyQt5.QtCore import *
import random
import time
import pandas as pd
'''This part of the code calls the window designed in QTDesigner'''
class simulacion(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
loadUi('simulacion.ui', self)
self.setStyle(QStyleFactory.create('Fusion'))
self.numsim = 10000000
self.pushButton.clicked.connect(self.calibracion)
self.pushButton_2.clicked.connect(self.save)
def cerrar(self):
self.close()
def calibracion(self):
self.montecarlo(self.numsim)
def save(self, data):
file,_=QFileDialog.getSaveFileName(self,'Guardar Archivo de Simulación','','(*.csv)')
if file:
df = pd.DataFrame(data)
df.to_csv(file,sep=';',index=False,encoding='utf-8')
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = simulacion()
widget.show()
sys.exit(app.exec_())
这部分代码是我描述将在蒙特卡罗算法中使用的函数的地方。其中指定的文本应该显示在QTextEdit中重要的是要提到在Montecarlo函数中,生成数据列表,这是保持所有模拟执行的内容。此变量是必需的,以便可以执行模拟类中的保存功能
parametros = [['Area', 0, 5]]
def generar_aleatorio():
aleatorio = []
for i in range(len(parametros)):
aleatorio.append(random.uniform(parametros[i][1],parametros[i][2]))
return aleatorio
def area(x1):
area = 3.1416 * x1**2
return area
def estado(starttime,last_print,contador, n, area):
global ult_print
acttime = time.time()
if acttime - last_print >= 2:
avg_time_per_run = (acttime - starttime) / (contador + 1)
timestr = time.strftime("%H:%M:%S", time.gmtime(round(avg_time_per_run * (n - (contador + 1)))))
text = ('Simulacion %i de %i - Tiempo estimado restante: %s\n' % (contador, n,timestr)+'Area = %5.3f' % (area)+'\n\n')
self.textEdit.moveCursor(QTextCursor.End)
self.textEdit.insertPlainText(text)
self.textEdit.moveCursor(QTextCursor.End)
ult_print = time.time()
return text
def montecarlo(n):
global ult_print
text='Iniciando iteraciones con {} repeticiones...\n\n'.format(n)
#self.textEdit.setText(text)
#self.textEdit.moveCursor(QTextCursor.End)
ult_print = time.time()
starttime = time.time()
contador = 0
data=[]
num_sim=[]
#QApplication.setOverrideCursor(Qt.WaitCursor)
while contador < n:
contador +=1
#Generar el numero aleatorio
z = generar_aleatorio()
#Simulacion del modelo con el numero aleatorio
y = area(z[0])
#Calculo de la funcion objetivo
estado(starttime,ult_print,contador,n,y)
data.append(list(z+y))
#QApplication.setOverrideCursor(Qt.CustomCursor)
答案 0 :(得分:0)
适当的解决方案是在另一个线程中执行阻塞任务,并通过信号将数据发送到主线程中的GUI,Qt禁止使用processEvents
从主要线程更新GUI。强制GUI更新一些不保证正确操作的参数,您可以在以下链接中阅读有关此主题的更多信息:Should I use QCoreApplication::processEvents() or QApplication::processEvents()?。
在下面的示例中,我将使用2个信号旁边的本机python线程,一个将发送文本,另一个将发送数据。
import random
import sys
import time
from threading import Thread
import pandas as pd
from PyQt5.QtCore import QObject, pyqtSignal, Qt
from PyQt5.QtWidgets import QApplication, QFileDialog, QStyleFactory, QMainWindow
from PyQt5.uic import loadUi
parametros = [['Area', 0, 5]]
def generar_aleatorio():
return random.uniform(*parametros[0][1:])
def area(x1):
area = 3.1416 * x1 ** 2
return area
class Helper(QObject):
send_signal = pyqtSignal(str)
data_signal = pyqtSignal(list)
helper = Helper()
def estado(starttime, last_print, contador, n, area):
acttime = time.time()
if acttime - last_print <= 2:
avg_time_per_run = (acttime - starttime) / (contador + 1)
timestr = time.strftime("%H:%M:%S", time.gmtime(round(avg_time_per_run * (n - (contador + 1)))))
text = 'Simulacion %i de %i - Tiempo estimado restante: %s\n' % (contador, n, timestr) \
+ 'Area = %5.3f\n\n' % area
helper.send_signal.emit(text)
def montecarlo(n):
data = []
text = 'Iniciando iteraciones con {} repeticiones...\n\n'.format(n)
helper.send_signal.emit(text)
ult_print = time.time()
starttime = time.time()
for contador in range(n):
z = generar_aleatorio()
y = area(z)
estado(starttime, ult_print, contador + 1, n, y)
ult_print = time.time()
time.sleep(0.001)
data.append([z, y])
helper.data_signal.emit(data)
class simulacion(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
loadUi('simulacion.ui', self)
self.setStyle(QStyleFactory.create('Fusion'))
self.numsim = 10000000
self.pushButton.clicked.connect(self.calibracion)
self.pushButton_2.clicked.connect(self.save)
def calibracion(self):
thread = Thread(target=montecarlo, args=(self.numsim,))
helper.send_signal.connect(self.textEdit.append, Qt.QueuedConnection)
helper.data_signal.connect(self.obtener_resultados)
thread.start()
def obtener_resultados(self, data):
self.data = data
def save(self, data):
file, _ = QFileDialog.getSaveFileName(self, 'Guardar Archivo de Simulación', '', '(*.csv)')
if file:
df = pd.DataFrame(self.data)
df.to_csv(file, sep=';', index=False, encoding='utf-8')
app = QApplication(sys.argv)
w = simulacion()
w.show()
sys.exit(app.exec_())
答案 1 :(得分:-2)
将QApplication.processEvents()
方法移到while contador <n:
不太好,但确实有效。
def montecarlo(self, n):
#----QApplication.processEvents() # ---
global ult_print
text = 'Iniciando iteraciones con {} repeticiones...\n\n'.format(n)
self.textEdit.setText(text)
self.textEdit.moveCursor(QTextCursor.End)
ult_print = time.time()
starttime = time.time()
contador = 0
self.data = []
self.num_sim= []
QApplication.setOverrideCursor(Qt.WaitCursor)
while contador < n:
contador += 1
#Generar el numero aleatorio
z = self.generar_aleatorio()
#Simulacion del modelo con el numero aleatorio
y = self.area(z[0])
#Calculo de la funcion objetivo
self.estado(starttime,ult_print,contador,n,y)
QApplication.processEvents() # +++
QApplication.setOverrideCursor(Qt.CustomCursor)