多功能调用QTimer主窗口挂起
问题描述
现在我尝试向计时器函数添加另一个函数,当我尝试运行它时,输出窗口挂起。用于同时运行两个函数的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秒运行一次我在live news方法中定义的foreach循环。如何存档此文件?
解决方案
问题不在于多个QTimer,而在于在主线程中使用requests.get()和time.睡眠(),因为它们阻塞了图形用户界面所在的事件循环,因此您必须在辅助线程上运行它。
在下面的部分中,我展示了一个示例:
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_())
相关文章