此文档仅记录本人遇到的问题及解决办法,并非涵盖所有
最近写一个股价监控小程序,在改进为界面程序后,每次运行到耗时方法时界面就卡死,无响应,花费了很长事件才把问题解决了,记录一下
程序在主线程中执行,当主程序中有一个事件比较耗时时,主程序就会等耗时事件处理完才会进行下一步,此时界面就会卡死出现无响应的状态
main.py
import sys
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication
import stock_price_wring
if __name__ == '__main__':
app = QApplication(sys.argv)
mainW = QMainWindow()
ui = monitor.Ui_MainWindow()
ui.setupUi(mainW)
mainW.show()
sys.exit(app.exec_())
调用的耗时代码
def do_monitor(monitor_info, send_mail, authorization, receive_mail):
"""
预警监控
:param monitor_info: 监控条件数据
:param send_mail: 发件邮箱
:param authorization: 授权码
:param receive_mail: 收件邮箱
:return: 回显信息
"""
now_date = datetime.datetime.now().strftime('%Y-%m-%d')
for item in monitor_info:
info = get_stock_info(item[0])
# 判断监控方式
if item[2] == 0:
# 价格下跌至
if float(info['price'][0]) <= item[1]:
text = info['time'][0] + ' ' + info['name'][0] + '触发预警条件:股价跌到' + str(item[1]) + '元,提醒您及时关注'
send_content = info['name'][0] + '触发预警条件:股价跌到' + str(item[1]) + '元,提醒您及时关注' + '\n\n' + '股票代码:' + info['code'][0] + '\n' + '股票名称:' + info['name'][0] + '\n' + '预警周期:当日' + '\n' + '预警指标:股价' + '\n' + '时\t\t间:' + now_date + ' ' + info['time'][0]
res = do_send_mail(send_mail, authorization, receive_mail, send_content)
monitor_info.remove(item)
return text+'\n'+res
elif item[2] == 1:
# 价格上涨至
if float(info['price'][0]) >= item[1]:
text = info['time'][0] + ' ' + info['name'][0] + '触发预警条件:股价涨到' + str(item[1]) + '元,提醒您及时关注'
send_content = info['name'][0] + '触发预警条件:股价涨到' + str(item[1]) + '元,提醒您及时关注' + '\n\n' + '股票代码:' + info['code'][0] + '\n' + '股票名称:' + info['name'][0] + '\n' + '预警周期:当日' + '\n' + '预警指标:股价' + '\n' + '时\t\t间:' + now_date + ' ' + info['time'][0]
res = do_send_mail(send_mail, authorization, receive_mail, send_content)
monitor_info.remove(item)
return text+'\n'+res
else:
return ''
主线程只执行界面显示
子线程中执行耗时任务
信号
)子线程中定义信号和发送信号
# 实例化一个信号
signal = pyqtSignal(str)
# 发送信号
self.signal.emit(text)
主线程中接收信号
# 实例化线程
self.thread = MonitorThread(self)
# 绑定接收线程信号的方法
self.thread.signal.connect(self.receive_signal)
def receive_signal(self, text):
"""
接收子线程传送的数据 回显至浏览框
:param text:
"""
self.textBrowser.append(text)
if __name__ == '__main__':
log_dir = os.path.join(os.getcwd(), 'log')
if not os.path.exists(log_dir):
os.mkdir(log_dir)
cgitb.enable(format='text', logdir=log_dir)
app = QApplication(sys.argv)
myWin = MyMainForm()
myWin.show()
sys.exit(app.exec_())
窗口类
class MyMainForm(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MyMainForm, self).__init__(parent)
self.setupUi(self)
# 实例化线程
self.thread = MonitorThread(self)
# 窗口启动自动执行获取配置数据
self.read_base_info()
# 按钮点击事件
self.chooseBtn.clicked.connect(self.choose_file)
self.runBtn.clicked.connect(self.start_monitoring)
# 接收线程信号,进行数据回显
self.thread.signal.connect(self.receive_signal)
def read_base_info(self):
"""
获取基础数据:发件箱,授权码,收件箱
"""
base_info = pd.read_table('./baseinfo.txt', header=None)
self.sendMail.setText(base_info[0][0])
self.authorization.setText(base_info[0][1])
self.receiveMail.setText(base_info[0][2])
def choose_file(self):
"""
选择预警信息的存储文件 -> Excel
"""
root = tkinter.Tk()
root.withdraw()
filepath = filedialog.askopenfilename()
self.filePath.setText(filepath)
def start_monitoring(self):
"""
开始监控 启动子线程 调用子线程接收数据的方法
"""
# 数据整理
file_path = self.filePath.text()
send_mail = self.sendMail.text()
authorization = self.authorization.text()
receive_mail = self.receiveMail.text()
base_info = {'file_path': file_path,
'send_mail': send_mail,
'authorization': authorization,
'receive_mail': receive_mail}
# 调用线程接收主线程传递数据的方法
self.thread.accept_info(base_info)
# 开启子线程
self.thread.start()
def receive_signal(self, text):
"""
接收子线程传送的数据 回显至浏览框
:param text:
"""
self.textBrowser.append(text)
子线程类
class MonitorThread(QThread):
# 实例化一个信号
signal = pyqtSignal(str)
def __init__(self, main_form):
super(MonitorThread, self).__init__()
self.file_path = ''
self.send_mail = ''
self.authorization = ''
self.receive_mail = ''
self.main_form = main_form
def accept_info(self, base_info):
"""
接收主线程发送的数据
:param base_info:
"""
self.file_path = base_info.get('file_path')
self.send_mail = base_info.get('send_mail')
self.authorization = base_info.get('authorization')
self.receive_mail = base_info.get('receive_mail')
def run(self):
"""
子线程运行方法,执行耗时任务
"""
# 获取监控信息
monitor_info = get_monitor_info(self.file_path)
# 循环监控
while True:
# 调用方法 返回信息
text = do_monitor(monitor_info, self.send_mail, self.authorization, self.receive_mail)
# 发送信号
self.signal.emit(text)
time.sleep(1)