Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在QLabel中进行计算时实时更新文本,而不冻结接口?_Python_Python 3.x_Pyqt_Pyqt5_Qthread - Fatal编程技术网

Python 如何在QLabel中进行计算时实时更新文本,而不冻结接口?

Python 如何在QLabel中进行计算时实时更新文本,而不冻结接口?,python,python-3.x,pyqt,pyqt5,qthread,Python,Python 3.x,Pyqt,Pyqt5,Qthread,关于Q标签中的实时更新,我有一个问题,因为当我单击“开始”按钮时,屏幕在执行计算时会保持静止几秒钟,但我需要的是,在QLabel中,随着模拟的进行,会显示状态消息。我尝试过使用线程,但我不太了解它,因为它不起作用,如果有人能帮助我,我将不胜感激,因为我在Pyqt5中没有处理太多线程问题。(我不明白) 多谢各位 我附上了界面的代码和图像: 接口 执行前: 执行期间: 执行后: Codigo import sys from PyQt5.QtWidgets import QStyleFact

关于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_())
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函数中,会生成数据列表,这是保持所有模拟执行的原因。此变量是必需的,以便可以执行simulation类中的save函数

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)
parametros=['Area',0,5]]
定义generar_aleatorio():
aleatorio=[]
对于范围内的i(len(parametros)):
aleatorio.append(random.uniform(parametros[i][1],parametros[i][2]))
返回阿莱托里奥
def区域(x1):
面积=3.1416*x1**2
返回区
def estado(开始时间、最后打印、contador、n、区域):
全球印刷
acttime=time.time()
如果acttime-上次打印>=2:
平均每次运行时间=(acttime-starttime)/(contador+1)
timestr=time.strftime(“%H:%M:%S”,time.gmtime(每运行一次的平均时间*(n-(contador+1(()))))
text=('simulation%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(文本)
self.textEdit.moveCursor(QTextCursor.End)
ult_print=time.time()
返回文本
def蒙特卡洛(n):
全球印刷
text='Iniciando iteraciones con{}重复性…\n\n'。格式(n)
#self.textEdit.setText(文本)
#self.textEdit.moveCursor(QTextCursor.End)
ult_print=time.time()
starttime=time.time()
康塔多=0
数据=[]
num_sim=[]
#QApplication.setOverrideCursor(Qt.WaitCursor)
当contador
适当的解决方案是在另一个线程中执行阻塞任务,并通过信号将数据发送到主线程中的GUI,Qt禁止从主线程以外的线程更新GUI,使用
processEvents
强制GUI更新一些不保证正确操作的参数,您可以在以下链接中阅读有关此主题的更多信息:

在下面的示例中,我将在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_())
随机导入
导入系统
导入时间
从线程导入线程
作为pd进口熊猫
从PyQt5.QtCore导入QObject、pyqtSignal、Qt
从PyQt5.QtWidgets导入QApplication、QFileDialog、QStyleFactory、QMainWindow
从PyQt5.uic导入loadUi
参数=[['Area',0,5]]
定义generar_aleatorio():
返回random.uniform(*参数[0][1:)
def区域(x1):
面积=3.1416*x1**2
返回区
类帮助程序(QObject):
发送信号=pyqtSignal(str)
数据信号=pyqtSignal(列表)
helper=helper()
def estado(开始时间、最后打印、contador、n、区域):
acttime=time.time()

如果acttime-last_打印线程,您一直在尝试什么?一个QThread应该做你想做的事情。正如我在其他关于线程的答案中读到的那样,我可以做的是,文本的更新是在Qlabel中完成的,当它被处理时,但是我不太理解,你是这部分的初学者。我试图在我的代码中实现这个示例,但它不起作用,我犯了一个又一个错误,它没有起作用。首先,在每个montecarlo迭代中调用“self.estado(starttime,ultu_print,contador,n,y)”是一种糟糕的性能,尝试每运行10000次左右调用一次“if contador%10000==0”,这就是接口冻结的原因?。例如,我给出的代码很简单,因为我使用的代码在一段时间内使用了其他函数,如果我将迭代次数设置为1000,则需要一分钟。self.state每2秒打印一次,但您可以将时间增加到5秒,但是这个函数很简单,因为它只计算一个面积,所以我把迭代次数放高,这样就可以看到它所做的迭代。但是,在我配置信号时,如何调整线程,以便在执行计算时显示消息,我真的不明白它工作得很好,谢谢您的解决方案。我对GUI中的校准功能有疑问,特别是在第二行,有必要放置“Qt.QueuedConnection”?@Peter python的原理之一是:显式比隐式好,默认情况下连接是Qt.AutoConnection,由您指示PyQt决定,它将看到哪个更好,但这可能很危险。标志Qt.QueuedConnection面向位于不同线程中的元素之间的连接,因此,如果您想了解更多信息,最好明确连接类型: