Python 在线程中更改QObject样式表时出错 上下文

Python 在线程中更改QObject样式表时出错 上下文,python,multithreading,pyqt,pyqt5,qtstylesheets,Python,Multithreading,Pyqt,Pyqt5,Qtstylesheets,我想用python构建QObject动画。例如,我尝试设置QLineEdit对象背景的动画,以便在输入错误内容时发出“红色闪光”。函数正在工作,线程开始,我看到了动画,但当线程结束时,应用程序崩溃,没有错误跟踪。我只有 exit code -1073740940 这是我在网上找不到的 最小工作示例 这是我制作的一个mwe,以便您仅用一个文件复制此错误。您会注意到代码的重要部分在LoginDialog类中 from PyQt5.QtWidgets import QDialog, QLineEdi

我想用python构建QObject动画。例如,我尝试设置QLineEdit对象背景的动画,以便在输入错误内容时发出“红色闪光”。函数正在工作,线程开始,我看到了动画,但当线程结束时,应用程序崩溃,没有错误跟踪。我只有

exit code -1073740940
这是我在网上找不到的

最小工作示例 这是我制作的一个mwe,以便您仅用一个文件复制此错误。您会注意到代码的重要部分在LoginDialog类中

from PyQt5.QtWidgets import QDialog, QLineEdit, QVBoxLayout, QApplication
from threading import Thread
import time
import sys


class Ui_LoginUi(object):
    def setupUi(self, Ui_LoginUi):
        Ui_LoginUi.setObjectName("LoginUi")
        Ui_LoginUi.resize(293, 105)
        self.layout = QVBoxLayout(Ui_LoginUi)
        self.le_test = QLineEdit(Ui_LoginUi)
        self.layout.addWidget(self.le_test)


class LoginDialog(QDialog, Ui_LoginUi):

    def __init__(self):
        super(LoginDialog, self).__init__()
        self.setupUi(self)
        self.le_test.textChanged.connect(self.redFlashThreader)

    def redFlashThreader(self):
        self.redFlashTread1 = Thread(target=self.lineEdit_redFlash, args=[self.le_test])
        self.redFlashTread1.start()

    def lineEdit_redFlash(self, *args):
        inital_r = 255
        initial_g = 127
        initial_b = 127

        for i in range(64):
            initial_g += 2
            initial_b += 2
            time.sleep(0.005)
            args[0].setStyleSheet("background-color: rgb(255,{},{})".format(initial_g, initial_b))

        args[0].setStyleSheet("background-color: rgb(255,255,255")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = LoginDialog()
    dialog.show()
    sys.exit(app.exec_())
后果 如果您多次单击,应用程序将冻结并崩溃。我很想了解原因,但没有追溯,我觉得这相当困难。有时,它发生在第一次单击之后。我原以为这是一个线程冲突问题,但由于它只在第一个线程运行时发生,所以我不太确定。任何人都可以给我指出正确的方向或向我解释发生了什么事?

要在输入错误时实现“红色闪烁”,可以使用。基本上,当字段中的文本发生更改,并触发错误文本时,可以将背景更改为错误颜色。然后经过一定的时间,比如说2秒后,您可以重置字段颜色

from PyQt5.QtWidgets import QDialog, QLineEdit, QVBoxLayout, QApplication
from PyQt5.QtCore import QTimer 
import time
import sys

class Ui_LoginUi(object):
    def setupUi(self, Ui_LoginUi):
        Ui_LoginUi.setObjectName("LoginUi")
        Ui_LoginUi.resize(293, 105)
        self.layout = QVBoxLayout(Ui_LoginUi)
        self.le_test = QLineEdit(Ui_LoginUi)
        self.layout.addWidget(self.le_test)

class LoginDialog(QDialog, Ui_LoginUi):

    def __init__(self):
        super(LoginDialog, self).__init__()
        self.setupUi(self)

        self.invalid_color = 'background-color: #c91d2e'
        self.valid_color = 'background-color: #FFF'
        self.le_test.textChanged.connect(self.redFlashHandler)

    def redFlashHandler(self):
        if self.le_test.text() == 'test':
            self.le_test.setStyleSheet(self.invalid_color)

            # After 2000 ms, reset field color
            QTimer.singleShot(2000, self.resetFieldColor)

    def resetFieldColor(self):
        self.le_test.setStyleSheet(self.valid_color)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = LoginDialog()
    dialog.show()
    sys.exit(app.exec_())

您的问题允许分析以下方面:

1) 您不应该直接从另一个线程更新任何GUI元素 GUI的绘制是在主线程中完成的,因此GUI在任何情况下都不允许修改涉及从另一个线程绘制的任何属性,因此,如果开发人员这样做,则无法保证在本例中工作正常,这是错误的。欲了解更多信息,请阅读

在Qt的情况下,如果您想从另一个线程更新一些GUI元素,那么您应该通过某种方式(信号、QEvent、QMetaObject::invokeMethod()等)将信息发送到主线程,并在主线程中进行更新

因此,考虑到上述情况,使用信号的可能解决方案如下:

导入系统 导入时间 从线程导入线程 从PyQt5导入QtCore、QtGui、QtWidgets 类Ui_LoginUi(对象): def设置Ui(自我、用户界面和登录): Ui_LoginUi.setObjectName(“LoginUi”) Ui_LoginUi.resize(293105) layout=qtwidts.QVBoxLayout(Ui\u LoginUi) self.le_test=QtWidgets.QLineEdit(Ui_LoginUi) layout.addWidget(self.le_测试) 类LoginDialog(qtwidts.QDialog,Ui_LoginUi): colorChanged=QtCore.pyqtSignal(QtGui.QColor) 定义初始化(自): super(LoginDialog,self)。\uuuu init\uuuuu() self.setupUi(self) self.le_test.textChanged.connect(self.redFlashThreader) self.colorChanged.connect(self.on\u color\u change) @QtCore.pyqtSlot() def redFlashThreader(自): self.redFlashTread1=线程( target=self.lineEdit\u红色闪光,args=[self.le\u测试] ) self.redFlashTread1.start() def LINEDIT_红色闪烁(自身,*参数): 初始值=255 初始值=127 初始值b=127 对于范围(64)内的i: 初始值_g+=2 初始值b+=2 睡眠时间(0.005) self.colorChanged.emit(QtGui.QColor(255,首字母g,首字母b)) self.colorChanged.emit(QtGui.QColor(255、255、255)) @pyqtlot(QtGui.QColor) def on_color_change(自身,颜色): self.setStyleSheet(“QLineEdit{background color:%s}”%(color.name(),) “或 自选表格( QLineEdit{背景色:rgb(%d,%d,%d)} %(color.red()、color.green()、color.blue()) )""" 如果名称=“\uuuuu main\uuuuuuuu”: app=qtwidts.QApplication(sys.argv) dialog=LoginDialog() dialog.show() sys.exit(app.exec_()) 2) 在Qt中不需要使用线程来制作动画,而是应该使用QVariantAnimation、QPropertyAnimation等。 在GUI中,您应该避免使用线程,因为它带来的问题多于好处(例如,使信号队列饱和),所以将其作为最后手段使用。在这种情况下,您可以使用或:

2.1)QVariantAnimation 导入系统 从PyQt5导入QtCore、QtGui、QtWidgets 类Ui_LoginUi(对象): def设置Ui(自我、用户界面和登录): Ui_LoginUi.setObjectName(“LoginUi”) Ui_LoginUi.resize(293105) layout=qtwidts.QVBoxLayout(Ui\u LoginUi) self.le_test=QtWidgets.QLineEdit(Ui_LoginUi) layout.addWidget(self.le_测试) 类LoginDialog(qtwidts.QDialog,Ui_LoginUi): 定义初始化(自): super(LoginDialog,self)。\uuuu init\uuuuu() self.setupUi(self) self.le\u test.textChanged.connect(self.start\u动画) self.m_动画=QtCore.QVariantAnimation( 自己 startValue=QtGui.QColor(255、127、127), endValue=QtGui.QColor(255,255,255), 持续时间=1000, valueChanged=self.on\u color\u change, ) @QtCore.pyqtSlot() def start_动画(自): 如果self.m_animation.state()==QtCore.QAbstractAnimation.Running: self.m_animation.stop() self.m_animation.start() @pyqtSlot(QtCore.QVariant) @pyqtlot(QtGui.QColor) def on_color_change(自身,颜色): self.setStyleSheet(“QLineEdit{background color:%s}”%(color.name(),) “或 自选表格( QLineEdit{背景色:rgb(%d,%d,%d)} %(color.red()、color.green()、color.blue()) )""" 如果名称=“\uuuuu main\uuuuuuuu”: app=qtwidts.QApplication(sys.argv) dialog=LoginDialog() dialog.show() sys.exit(app.exec_()) 2.2)QPropertyAnimation 导入系统 从PyQt5导入QtCore、QtGui、QtWidgets 类LineEdit(QtWidgets.QLineEdit): backgroundColorChanged=QtCore.pyqtSignal(QtGui.QColor) def背景颜色(自身): 如果不是hasattr(self,“\u background\u color”): 自身背景_