Python中的冻结Qt GUI

Posted

技术标签:

【中文标题】Python中的冻结Qt GUI【英文标题】:Frozen Qt GUI in Python 【发布时间】:2014-07-15 17:17:07 【问题描述】:

我正在用 Python 中的 QT gui 编写一个计时器应用程序,它工作得很好,直到我使用少于 5 分钟的数字。当我使用大于 300 秒的数字时,它会冻结。应该在哪里出错?谢谢。 (现在只实现了倒计时)

from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from threading import Timer


class Drawer(QObject):
    def __init__(self,i=0,j=47):
        QObject.__init__(self)
        self.i=i
        self.j=j
        self.begin=self.j

    '''def run(self):
        self.exec_()'''
    def signal_emitter_upcount(self):
        print self.i  
        self.i=self.i+1
        print '\n'

    def signal_emitter_downcount(self): 
        self.emit(SIGNAL("asignal"))
        #timer.cancel()


    def connected_from_main_thread(self):
        '''
        called from main thread connected by signals
        '''
        if(self.j!=0): #for sure (numbers not < 0)
            self.j=self.j-1
        self.percent=int (100-(float (self.j)/float(self.begin)*100))#how many percent is done

        ui.lcdNumber_8.setProperty("value", time_format_converter(self.j)[-1])
        ui.lcdNumber_11.setProperty("value", time_format_converter(self.j)[-2])
        ui.lcdNumber_7.setProperty("value", time_format_converter(self.j)[-3])
        ui.lcdNumber_9.setProperty("value", time_format_converter(self.j)[-4])
        ui.lcdNumber_10.setProperty("value", time_format_converter(self.j)[-5])
        ui.progressBar.setProperty("value",self.percent)

        #ui.progressBar.setProperty("value",self.percent)
        #print self.j



class Watch(object):
    def __init__(self, type="Counter", seconds = 60):
        self.drawer = Drawer(j = seconds,i=0)
        if(type=="Countdown"):
            self.seconds = seconds + 1
            self.watch = Countdown(value = self.seconds)
        if(type=="Counter"):
            self.seconds = seconds + 1 
            self.watch = Counter(value = self.seconds)

class Countdown(object):
    def __init__(self, value=50):
        self.value=value

    def run_me(self):
        for x in xrange(1,self.value+2):
            timer = Timer(0.1*x, watch.drawer.signal_emitter_downcount)
            timer.start()
            '''if(x==self.value):
                timer.cancel()'''
    def stop_countdown(self):
        pass

class Counter(object):
    def __init__(self, value=30):
        self.value=value

    def run(self):
        for x in xrange(1,self.value+2):
            print gui_final.watch
            timer = Timer(0.1*x, watch.drawer.signal_emitter_upcount)
            timer.start()
            if(x==self.value+1):
                timer.cancel()

    def stop_counter(self):
        pass



try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(1024, 700)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.gridLayout_3 = QtGui.QGridLayout(self.centralwidget)
        self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3"))
        self.horizontalLayout = QtGui.QHBoxLayout()
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.lcdNumber_5 = QtGui.QLCDNumber(self.centralwidget)
        self.lcdNumber_5.setNumDigits(1)
        self.lcdNumber_5.setDigitCount(1)
        self.lcdNumber_5.setProperty("intValue", 0)
        self.lcdNumber_5.setObjectName(_fromUtf8("lcdNumber_5"))
        self.horizontalLayout.addWidget(self.lcdNumber_5)
        self.lcdNumber_6 = QtGui.QLCDNumber(self.centralwidget)
        self.lcdNumber_6.setNumDigits(1)
        self.lcdNumber_6.setDigitCount(1)
        self.lcdNumber_6.setProperty("intValue", 0)
        self.lcdNumber_6.setObjectName(_fromUtf8("lcdNumber_6"))
        self.horizontalLayout.addWidget(self.lcdNumber_6)
        self.line = QtGui.QFrame(self.centralwidget)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.line.sizePolicy().hasHeightForWidth())
        self.line.setSizePolicy(sizePolicy)
        self.line.setFrameShape(QtGui.QFrame.VLine)
        self.line.setFrameShadow(QtGui.QFrame.Sunken)
        self.line.setObjectName(_fromUtf8("line"))
        self.horizontalLayout.addWidget(self.line)
        self.lcdNumber_10 = QtGui.QLCDNumber(self.centralwidget)
        self.lcdNumber_10.setNumDigits(1)
        self.lcdNumber_10.setDigitCount(1)
        self.lcdNumber_10.setProperty("intValue", 0)
        self.lcdNumber_10.setObjectName(_fromUtf8("lcdNumber_10"))
        self.horizontalLayout.addWidget(self.lcdNumber_10)
        self.lcdNumber_9 = QtGui.QLCDNumber(self.centralwidget)
        self.lcdNumber_9.setNumDigits(1)
        self.lcdNumber_9.setDigitCount(1)
        self.lcdNumber_9.setProperty("intValue", 0)
        self.lcdNumber_9.setObjectName(_fromUtf8("lcdNumber_9"))
        self.horizontalLayout.addWidget(self.lcdNumber_9)
        self.line_2 = QtGui.QFrame(self.centralwidget)
        self.line_2.setFrameShape(QtGui.QFrame.VLine)
        self.line_2.setFrameShadow(QtGui.QFrame.Sunken)
        self.line_2.setObjectName(_fromUtf8("line_2"))
        self.horizontalLayout.addWidget(self.line_2)
        self.lcdNumber_7 = QtGui.QLCDNumber(self.centralwidget)
        self.lcdNumber_7.setNumDigits(1)
        self.lcdNumber_7.setDigitCount(1)
        self.lcdNumber_7.setProperty("intValue", 0)
        self.lcdNumber_7.setObjectName(_fromUtf8("lcdNumber_7"))
        self.horizontalLayout.addWidget(self.lcdNumber_7)
        self.lcdNumber_11 = QtGui.QLCDNumber(self.centralwidget)
        self.lcdNumber_11.setNumDigits(1)
        self.lcdNumber_11.setDigitCount(1)
        self.lcdNumber_11.setProperty("intValue", 0)
        self.lcdNumber_11.setObjectName(_fromUtf8("lcdNumber_11"))
        self.horizontalLayout.addWidget(self.lcdNumber_11)
        self.line_3 = QtGui.QFrame(self.centralwidget)
        self.line_3.setFrameShape(QtGui.QFrame.VLine)
        self.line_3.setFrameShadow(QtGui.QFrame.Sunken)
        self.line_3.setObjectName(_fromUtf8("line_3"))
        self.horizontalLayout.addWidget(self.line_3)
        self.lcdNumber_8 = QtGui.QLCDNumber(self.centralwidget)
        self.lcdNumber_8.setNumDigits(1)
        self.lcdNumber_8.setDigitCount(1)
        self.lcdNumber_8.setProperty("intValue", 0)
        self.lcdNumber_8.setObjectName(_fromUtf8("lcdNumber_8"))
        self.horizontalLayout.addWidget(self.lcdNumber_8)
        self.gridLayout_3.addLayout(self.horizontalLayout, 0, 0, 1, 3)
        self.horizontalLayout_2 = QtGui.QHBoxLayout()
        self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
        self.progressBar = QtGui.QProgressBar(self.centralwidget)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.progressBar.sizePolicy().hasHeightForWidth())
        self.progressBar.setSizePolicy(sizePolicy)
        self.progressBar.setProperty("value", 0)
        self.progressBar.setObjectName(_fromUtf8("progressBar"))
        self.horizontalLayout_2.addWidget(self.progressBar)
        self.gridLayout_3.addLayout(self.horizontalLayout_2, 1, 0, 1, 3)
        self.verticalLayout_2 = QtGui.QVBoxLayout()
        self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
        self.radioButton_2 = QtGui.QRadioButton(self.centralwidget)
        self.radioButton_2.setObjectName(_fromUtf8("radioButton_2"))
        self.verticalLayout_2.addWidget(self.radioButton_2)
        self.radioButton = QtGui.QRadioButton(self.centralwidget)
        self.radioButton.setObjectName(_fromUtf8("radioButton"))
        self.verticalLayout_2.addWidget(self.radioButton)
        self.gridLayout_3.addLayout(self.verticalLayout_2, 2, 0, 1, 1)
        self.gridLayout_2 = QtGui.QGridLayout()
        self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
        self.label = QtGui.QLabel(self.centralwidget)
        self.label.setObjectName(_fromUtf8("label"))
        self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
        self.label_2 = QtGui.QLabel(self.centralwidget)
        self.label_2.setObjectName(_fromUtf8("label_2"))
        self.gridLayout_2.addWidget(self.label_2, 0, 1, 1, 1)
        self.label_3 = QtGui.QLabel(self.centralwidget)
        self.label_3.setObjectName(_fromUtf8("label_3"))
        self.gridLayout_2.addWidget(self.label_3, 0, 2, 1, 1)
        self.spinBox = QtGui.QSpinBox(self.centralwidget)
        self.spinBox.setObjectName(_fromUtf8("spinBox"))
        self.gridLayout_2.addWidget(self.spinBox, 1, 0, 1, 1)
        self.spinBox_2 = QtGui.QSpinBox(self.centralwidget)
        self.spinBox_2.setObjectName(_fromUtf8("spinBox_2"))
        self.gridLayout_2.addWidget(self.spinBox_2, 1, 1, 1, 1)
        self.spinBox_3 = QtGui.QSpinBox(self.centralwidget)
        self.spinBox_3.setObjectName(_fromUtf8("spinBox_3"))
        self.gridLayout_2.addWidget(self.spinBox_3, 1, 2, 1, 1)
        self.gridLayout_3.addLayout(self.gridLayout_2, 2, 1, 1, 2)
        self.label_4 = QtGui.QLabel(self.centralwidget)
        self.label_4.setObjectName(_fromUtf8("label_4"))
        self.gridLayout_3.addWidget(self.label_4, 3, 0, 1, 1)
        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        self.gridLayout_3.addWidget(self.pushButton, 3, 1, 1, 1)
        self.pushButton_2 = QtGui.QPushButton(self.centralwidget)
        self.pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
        self.gridLayout_3.addWidget(self.pushButton_2, 3, 2, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1024, 25))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.pushButton.setCheckable(True)
        self.pushButton.pressed.connect(self.start_watch)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "Time_it!", None))
        self.radioButton_2.setText(_translate("MainWindow", "Counter", None))
        self.radioButton.setText(_translate("MainWindow", "Countdown", None))
        self.label.setText(_translate("MainWindow", "hr", None))
        self.label_2.setText(_translate("MainWindow", "min", None))
        self.label_3.setText(_translate("MainWindow", "sec", None))
        self.label_4.setText(_translate("MainWindow", "martin.bednar@hotmail.sk", None))
        self.pushButton.setText(_translate("MainWindow", "Start", None))
        self.pushButton_2.setText(_translate("MainWindow", "Stop", None))

    def start_watch(self,pressed = True):
        if(pressed):
            hrs = ui.spinBox.value()
            minutes = ui.spinBox_2.value()
            second = ui.spinBox_3.value()
            timeings=time_format_deconverter([hrs,minutes,second])
            global watch
            watch = Watch(type="Countdown", seconds = timeings)
            QObject.connect(watch.drawer,SIGNAL("asignal"),watch.drawer.connected_from_main_thread,Qt.QueuedConnection)
            watch.watch.run_me()




def time_format_converter(number): #99hours * 60 *60 *10 + 59minutes*60 *10 + 59seconds*10 + 9seconds/10 
    if(number>3599999): 
        return 8,8,8,8,8,8,8
    else:
        hours_1 = number//36000//10
        hours_2 = number//36000%10
        number = number - hours_1*360000 - hours_2*36000
        minutes_1 = number//600//10
        minutes_2 = number//600%10
        if(minutes_1>=6):
            minutes_1 = minutes_1 - 6
            if(hours_2!=9):
                hours_2 = hours_2 + 1
            if(hours_2==9):
                hours_2 = 0
                hours_1 = hours_1 + 1 
        number = number - minutes_1*600 - minutes_2*600
        seconds_1 = number//10//10
        seconds_2 = number//10%10
        seconds_10 = number%10

        if(seconds_1>=6):

            seconds_1 = seconds_1 - 6
            if(minutes_2!=9):
                minutes_2 = minutes_2 + 1
            if(minutes_2==9):
                minutes_2 = 0
                minutes_1 = minutes_1 + 1 
    return hours_1, hours_2, minutes_1, minutes_2, seconds_1, seconds_2, seconds_10

def time_format_deconverter(data):
    '''
    input [HR,MIN,SEC]
    output [SEC * 10]
    '''
    return data[0]* 36000 + data[1] * 600 + data[2] * 10

watch = 0 #create global object named watch

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

【问题讨论】:

这可能是问题***.com/questions/1595649/… 【参考方案1】:

您不能直接从另一个线程访问 gui 线程。没有理由在这样的简单计时器中使用线程。使用QTimer每秒“打勾”更新ui,通过QTime或python的time模块获取当前时间。

【讨论】:

以上是关于Python中的冻结Qt GUI的主要内容,如果未能解决你的问题,请参考以下文章

QT QThread::isrunning 冻结程序在 Pi

当 GL 更新大于 15 Hz 时 Qt UI 冻结

使用 Fbs/PyInstaller 冻结我的应用程序导致在另一台电脑上启动时无法执行 pyi_rth_qt5plugins

为啥我的 pyqt 信号错误会冻结 ui,直到调用另一个 python 函数

Qt 调试器在 OpenCV 中冻结

Qt:如何在特定时间内冻结某些按钮?