本文基于:windows 7 + python 3.4

知识点:

1. 将 time.sleep 替换为 QTimer

2. 将 time.sleep 放入到 QThread

3. 使用 QThread 自己的 sleep 方法

我们希望实现一个这样的小程序:

当点击开始按钮的时候,下面的文本标签每隔一秒自动加1。

一、直接用 time.sleep(1)

import timeclass TestWindow(QDialog):def __init__(self):# ...
btn1.clicked.connect(self.update) # 按钮连接到槽# ...def update(self):for i in range(20):time.sleep(1) # 每隔一秒self.sec += 1self.sec_label.setText(str(self.sec))

看起来没有任何逻辑上的错误。

那就运行一下看看,点击按钮。。。神马情况?主界面卡死了!如图

我猜测这可能与python的GIL问题有关:

  1. time库是纯python的,而PyQt的背后是Qt,这是纯C++的。

  2. 换句话说,就是time.sleep(1)时,并没有将CPU控制权交还给Qt,从而造成界面卡死

解决这个问题,既然不能用 python 的 time 库,那就用 PyQt 自己的 QTimer 类

二、使用 QTimer 类

class TestWindow(QDialog):def __init__(self):# ...
timer = QTimer() # 计时器timer.timeout.connect(self.update)btn1.clicked.connect(lambda :timer.start(1000)) # 启动计时器,间隔1秒btn2.clicked.connect(lambda :timer.stop())def update(self):self.sec += 1self.sec_label.setText(str(self.sec))

再运行一下。。。 OK,搞定!如图:

完整代码:

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sysclass TestWindow(QDialog):def __init__(self):super().__init__()self.sec = 0btn1 = QPushButton("Start", self)btn2 = QPushButton("Stop", self)self.sec_label = QLabel(self)layout = QGridLayout(self)layout.addWidget(btn1,0,0)layout.addWidget(btn2,0,1)layout.addWidget(self.sec_label,1,0,1,2)timer = QTimer()timer.timeout.connect(self.update) # 计时器挂接到槽:updatebtn1.clicked.connect(lambda :timer.start(1000))btn2.clicked.connect(lambda :timer.stop())def update(self):self.sec += 1self.sec_label.setText(str(self.sec))app=QApplication(sys.argv)
form=TestWindow()
form.show()
app.exec_()

三、将 time.sleep 放入到 QThread

解决这个问题的另外一个思路:开一个线程,专门用于计时(即:专门运行 time.sleep)

在 QThread 中使用 time.sleep 和 for 循环,无压力!

当然,线程与主窗口的通信使用了信号/槽。

代码如下:

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import timeclass TestWindow(QDialog):def __init__(self):super().__init__()btn1 = QPushButton("Start", self)btn2 = QPushButton("Stop", self)self.sec_label = QLabel(self)layout = QGridLayout(self)layout.addWidget(btn1,0,0)layout.addWidget(btn2,0,1)layout.addWidget(self.sec_label,1,0,1,2)thread = MyThread() # 创建一个线程
        thread.sec_changed_signal.connect(self.update) # 线程发过来的信号挂接到槽:updatebtn1.clicked.connect(lambda :thread.start())btn2.clicked.connect(lambda :thread.terminate()) # 线程中止def update(self, sec):  self.sec_label.setText(str(sec))class MyThread(QThread):  sec_changed_signal = pyqtSignal(int) # 信号类型:intdef __init__(self, sec=1000, parent=None):  super().__init__(parent)self.sec = sec # 默认1000秒def run(self):  for i in range(self.sec):self.sec_changed_signal.emit(i)  #发射信号time.sleep(1)app = QApplication(sys.argv)
form = TestWindow()
form.show()
app.exec_()

4. QThread 自身也有一个 sleep 方法

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *import sysclass Test(QDialog):def __init__(self,parent=None):super().__init__(parent)self.file_list = QListWidget()self.btn = QPushButton('Start')layout = QGridLayout(self)layout.addWidget(self.file_list,0,0,1,2)layout.addWidget(self.btn,1,1)self.thread = Worker()self.thread.file_changed_signal.connect(self.update_file_list)self.btn.clicked.connect(self.thread_start)def update_file_list(self, file_inf):self.file_list.addItem(file_inf)def thread_start(self):self.btn.setEnabled(False)self.thread.start()class Worker(QThread):file_changed_signal = pyqtSignal(str) # 信号类型:strdef __init__(self, sec=0, parent=None):super().__init__(parent)self.working = Trueself.sec = secdef __del__(self):self.working = Falseself.wait()def run(self):while self.working == True:self.file_changed_signal.emit('当前秒数:{}'.format(self.sec))self.sleep(1)self.sec += 1app = QApplication(sys.argv)
dlg = Test()
dlg.show()
sys.exit(app.exec_())

补:QObject -> moveToThread 方式应用 QThread

from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlotimport time
import sysclass Worker(QObject):finished = pyqtSignal()intReady = pyqtSignal(int)@pyqtSlot()def work(self): # A slot takes no paramsfor i in range(1, 100):time.sleep(1)self.intReady.emit(i)self.finished.emit()class Form(QWidget):def __init__(self):super().__init__()self.label = QLabel("0")# 1 - create Worker and Thread inside the Formself.worker = Worker()  # no parent!self.thread = QThread()  # no parent!
self.worker.intReady.connect(self.updateLabel)self.worker.moveToThread(self.thread)self.worker.finished.connect(self.thread.quit)self.thread.started.connect(self.worker.work)#self.thread.finished.connect(app.exit)
self.thread.start()self.initUI()def initUI(self):grid = QGridLayout()self.setLayout(grid)grid.addWidget(self.label,0,0)self.move(300, 150)self.setWindowTitle('thread test')def updateLabel(self, i):self.label.setText("{}".format(i))#print(i)
app = QApplication(sys.argv)
form = Form()
form.show()
sys.exit(app.exec_())

PyQt5 笔记(04):主窗口卡死问题相关推荐

  1. mfc e将控件置于窗口顶层_PyQt5学习笔记04 - QWidget窗口控件基类

    本来这一篇是想写一下怎么使用Qt Designer去设计一个界面的,但是我现在通常都是用代码去直接写界面很少用设计器.因为Qt Designer并不是为了python而写的,所以用起来不是很方便.很多 ...

  2. pyqt5实战开发主窗口加布局

    # -*- coding: utf-8 -*-'''[简介]PyQt5中 QDockWidget 例子'''import sys from PyQt5.QtCore import * from PyQ ...

  3. Linux学习笔记(二) -- Linux学习笔记(二) – 解决VMware主窗口中的虚拟机窗口太小的方法

    1.问题描述 在虚拟机中安装完ubuntu操作系统后,我们会发现ubuntu界面在主窗口中占比很小,如下图所示: 这给操作带来了极大的不便. 2.解决步骤 1.在VMware中启动ubuntu系统: ...

  4. pyqt5笔记 — 重写窗口方法closeEvent()的两种方式

    @[TOC](pyqt5笔记 - 重写窗口方法closeEvent()的两种方式) 一.重写的作用 在开发过程中,经常会遇到一种需求:服务器端在主动发出一些信息给客户端,而在用户端关闭UI的时候,需要 ...

  5. python PyQt5 QMainWindow类(Qt主窗口框架,主窗口提供了用于构建应用程序用户界面的框架)

    https://doc.qt.io/qtforpython/PySide2/QtWidgets/QMainWindow.html?highlight=qmainwindow#PySide2.QtWid ...

  6. pyqt 子窗口控制主窗口绘图_实战PyQt5: 005-主窗口QMainWindow

    QMainWindow简介 在桌面应用中,一个应用软件通常都会包含一个主窗口,主窗口是承载所有控件的窗体, 在PyQt5中常用的主窗体有两种QMainWindow和QDialog,他们也都继承自QWi ...

  7. pyqt5子窗口跳出主窗口_弹出式窗口与 可用性,转换和跳出率

    pyqt5子窗口跳出主窗口 Written by Cassandra Naji 由卡珊德拉·纳吉 ( Cassandra Naji)撰写 They go by many names - modal w ...

  8. c++ dll发消息到主窗口_PyQt5学习笔记(五)窗口图形绘制

    PyQt5提供了绘制图形的API,支持绘制: 文本 各种图形(直线,点,椭圆,弧,扇形,多边形等) 图像 绘制图形需要一个类QPainter.基本的绘制过程: # 创建QPainter对象 paint ...

  9. QT学习笔记(六):Qt5主窗口框架示例

    QT学习笔记(五):Qt5主窗口框架代码示例 一.添加编辑菜单:并在下拉菜单和工具栏中添加"打开文件"动作菜单 #include <QToolButton> #incl ...

最新文章

  1. RxJava的初步认识
  2. mysql 业务账户_mysql的事务
  3. tinyint对应什么数据类型_学习西门子S7-200系列PLC不得不掌握的数据类型
  4. C语言实现Floyd-Warshall(弗洛伊德算法)(附完整源码)
  5. java map的理解_java中的hashmap理解
  6. windows下安装mysql 开机启动
  7. 新西兰储备银行数据遭泄露
  8. 全球闪存供应紧张 新iPhone涨价只是开始
  9. 聊聊rsocket load balancer的Ewma
  10. Python爬虫实战, QQ空间自动点赞
  11. 打印服务器后台程序没有运行,win10遇到“打印后台程序服务没有运行”的解决方法...
  12. zimbra更换服务器域名
  13. chm提示 已取消到该网页的导航的解决方法
  14. 帆软报表入门操作(一)
  15. PTA: 6-8 剩余不足 (10分)(c语言)
  16. 醉月湖畔,为谁染红妆
  17. 华为硬件工程师社招机考题库_华为硬件工程师笔试、面试题
  18. 掌握这些PDF转Word方法,从此你就是大神的存在
  19. 蛮力法/01背包问题
  20. html设置表单里面字体格式为中文,html设置字体样式 html怎么设置字体样式 html字体怎么设置...

热门文章

  1. 记一次修复被篡改的IE首页
  2. 为WordPress添加favicon图标
  3. 写了一个好玩的小软件, 监视鼠标以及键盘的动作, 全局钩子. HowTired
  4. Leetcode PHP题解--D54 937. Reorder Log Files
  5. 数字图像处理的Matlab实现(1)—绪论
  6. 禁止微信下拉 露出黑色背景
  7. 宣告放弃社交后,支付宝把希望放在了“信息流”上
  8. 一步步分析AI如何玩Flappy Bird
  9. 大话App测试2.0笔记2
  10. 获取基目录,它由程序集冲突解决程序用来探测程序集