【问题标题】:Multiple function call QTimer Mainwindow hang多个函数调用 QTimer Mainwindow 挂起
【发布时间】:2019-07-18 09:26:57
【问题描述】:

现在我正在尝试向计时器功能添加一个更多功能,当我尝试运行它时,输出窗口会挂起。 QTimer 用来同时运行两个函数与 timer.start(1000) 有什么不同?下面是我正在使用的代码。

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import requests
import json
import xmltodict
import time 

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.widget_2 = QtWidgets.QWidget(self.centralwidget)
        self.widget_2.setObjectName("widget_2")
        self.label = QtWidgets.QLabel(self.widget_2)
        self.label.setGeometry(QtCore.QRect(40, 30, 181, 41))
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.widget_2)
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setObjectName("widget")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label_2 = QtWidgets.QLabel(self.widget)
        self.label_2.setObjectName("label_2")
        self.verticalLayout_2.addWidget(self.label_2, 0, QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
        self.line = QtWidgets.QFrame(self.widget)
        self.line.setFrameShape(QtWidgets.QFrame.HLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.verticalLayout_2.addWidget(self.line)
        self.label_3 = QtWidgets.QLabel(self.widget)
        self.label_3.setObjectName("label_3")
        self.verticalLayout_2.addWidget(self.label_3, 0, QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
        spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout_2.addItem(spacerItem)
        self.horizontalLayout.addWidget(self.widget)
        self.widget_3 = QtWidgets.QWidget(self.centralwidget)
        self.widget_3.setObjectName("widget_3")
        self.horizontalLayout.addWidget(self.widget_3)
        MainWindow.setCentralWidget(self.centralwidget)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(
            _translate(
                "MainWindow",
                '<html><head/><body><p><span style=" font-size:28pt;"></span></p></body></html>',
            )
        )
        self.label_2.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:14pt;\">Header</span></p></body></html>"))
        self.label_3.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:12pt;\">News</span></p></body></html>"))


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        timer = QtCore.QTimer(self)
        timer.timeout.connect(self.data)
        timer.timeout.connect(self.liveNews)
        timer.start(1000)
        self.data()
        self.liveNews()

    def data(self):
        time_str = QTime.currentTime().toString()
        self.label.setText(
            '<html><head/><body><p><span style=" font-size:28pt;">{}</span></p></body></html>'.format(
                time_str
            )
        )

    def liveNews(self):
        _translate = QtCore.QCoreApplication.translate
        liveNews_url = 'https://timesofindia.indiatimes.com/rssfeedstopstories.cms'
        response = requests.get(liveNews_url)
        result = response.content
        xml = xmltodict.parse(result)
        resp_json = json.loads(json.dumps(xml))
        for news in resp_json['rss']['channel']['item']:
            self.label_2.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:14pt;\">" + resp_json['rss']['channel']['title'] +"</span></p></body></html>"))
            self.label_3.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-size:12pt;word-wrap: break-word\">" + news['title'] + "</span></p></body></html>"))
            time.sleep(5)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

请告诉我解决问题。

我还想每 5 秒运行一次我在实时新闻方法中定义的 foreach 循环。我该如何存档?

【问题讨论】:

    标签: python pyqt python-requests pyqt5


    【解决方案1】:

    问题不在于多个 QTimer,而是在主线程中使用 requests.get() 和 time.sleep(),因为它们阻塞了 GUI 所在的事件循环,而您必须在辅助线程上运行它线程。

    在下面的部分中,我将展示一个示例:

    import json
    
    import requests
    import xmltodict
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Timer(QtCore.QObject):
        datetimeChanged = QtCore.pyqtSignal(QtCore.QTime)
    
        def __init__(self, parent=None):
            super(Timer, self).__init__(parent)
            self.m_timer = QtCore.QTimer(self, timeout=self.onTimeout)
    
        @property
        def interval(self):
            return self.m_timer.interval()
    
        @interval.setter
        def interval(self, v):
            self.m_timer.setInterval(v)
    
        @QtCore.pyqtSlot()
        def start(self):
            self.m_timer.start()
            self.onTimeout()
    
        @QtCore.pyqtSlot()
        def stop(self):
            self.m_timer.stop()
    
        @QtCore.pyqtSlot()
        def onTimeout(self):
            dt = QtCore.QTime.currentTime()
            self.datetimeChanged.emit(dt)
    
    
    class LiveNewsManager(QtCore.QObject):
        titleChanged = QtCore.pyqtSignal(str)
        contentChanged = QtCore.pyqtSignal(dict)
    
        def __init__(self, parent=None):
            super(LiveNewsManager, self).__init__(parent)
            self.m_timer = QtCore.QTimer(self, timeout=self.onTimeout)
    
        @property
        def interval(self):
            return self.m_timer.interval()
    
        @interval.setter
        def interval(self, v):
            self.m_timer.setInterval(v)
    
        @QtCore.pyqtSlot()
        def start_request(self):
            url = "https://timesofindia.indiatimes.com/rssfeedstopstories.cms"
            response = requests.get(url)
            xml = xmltodict.parse(response.content)
            resp_json = json.loads(json.dumps(xml))
            channel = resp_json["rss"]["channel"]
            self.titleChanged.emit(channel["title"])
            self.m_iterator = iter(channel["item"])
            self.m_timer.start()
            self.onTimeout()
    
        @QtCore.pyqtSlot()
        def onTimeout(self):
            try:
                item = next(self.m_iterator)
                self.contentChanged.emit(item)
            except StopIteration:
                self.m_timer.stop()
                self.start_request()
            except Exception as e:
                pass
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
    
            self.m_time_label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
            self.m_header_label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
            self.m_content_label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
    
            line = QtWidgets.QFrame(
                frameShape=QtWidgets.QFrame.HLine,
                frameShadow=QtWidgets.QFrame.Sunken,
            )
    
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
    
            vlay = QtWidgets.QVBoxLayout(central_widget)
    
            hlay = QtWidgets.QHBoxLayout()
            hlay.addWidget(self.m_time_label)
    
            vlay2 = QtWidgets.QVBoxLayout()
            vlay2.addWidget(self.m_header_label)
            vlay2.addWidget(line)
            vlay2.addWidget(self.m_content_label)
            hlay.addLayout(vlay2, stretch=1)
    
            vlay.addLayout(hlay)
            vlay.addStretch()
    
            self.resize(640, 480)
    
            timer = Timer(self)
            timer.interval = 1000
            timer.datetimeChanged.connect(self.update_time)
            timer.start()
    
            thread = QtCore.QThread(self)
            thread.start()
    
            self.m_worker = LiveNewsManager()
            self.m_worker.interval = 5 * 1000
            self.m_worker.moveToThread(thread)
            self.m_worker.titleChanged.connect(self.update_header)
            self.m_worker.contentChanged.connect(self.update_content)
            QtCore.QTimer.singleShot(0, self.m_worker.start_request)
    
        @QtCore.pyqtSlot(QtCore.QTime)
        def update_time(self, dt):
            self.m_time_label.setText(
                """<html><head/><body><p><span style=" font-size:28pt;">{}</span></p></body></html>""".format(
                    dt.toString()
                )
            )
    
        @QtCore.pyqtSlot(str)
        def update_header(self, header):
            self.m_header_label.setText(
                """<html><head/><body><p><span style=\" font-size:14pt;\">{}</span></p></body></html>""".format(
                    header
                )
            )
    
        @QtCore.pyqtSlot(dict)
        def update_content(self, content):
            self.m_content_label.setText(
                """<html><head/><body><p><span style=\" font-size:12pt;word-wrap: break-word\">{}</span></p></body></html>""".format(
                    content["title"]
                )
            )
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-07
      • 2019-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-16
      • 2015-07-04
      相关资源
      最近更新 更多