前段时间基于pyqt5开发了一个小软件,虽然之前没有接触过qt,但是使用过一段时间的python,主要写一些功能性脚本。
小软件的功能是在屏幕上美观地实时显示键盘的输入,主要适用于视频/直播教学的使用环境。
开发用时不到一天,期间查了许多的文章与文档,翻过了许多的坑,而且看到的一些教程还有pyqt4的,还得查询最新的官方文档进行新版本的兼容。
当时翻阅的主要是qt的官方文档(因为pyqt的文档不太好找),虽然是C++的,但内容基本一致,几乎没有转换到python的门槛。
解决方法:使用pyqt自带的QTimer,包括窗口渐隐之类的动画,都需要用QTimer实现,否则会导致线程阻塞。
首先,对于动态增加控件,查阅官方文档后,应使用
self.layout.addWidget(widget)
对于动态删除控件,应使用
self.layout.itemAt(i).widget().deleteLater()
官方文档中仅有deleteLater()
方法,其余的delete()
以及sip.delete(widget)
经试验都是不对的。
具体效果请参照下面的例子:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
'''pyqt5动态添加删除控件'''
class DynAddObject(QDialog):
def __init__(self, parent=None):
super(DynAddObject, self).__init__(parent)
self.widgetList = []
addButton = QPushButton(u"添加控件")
delBUtton = QPushButton(u"删除控件")
self.layout = QGridLayout()
self.layout.addWidget(addButton, 1, 0)
self.layout.addWidget(delBUtton, 2, 0)
self.setLayout(self.layout)
addButton.clicked.connect(self.add)
delBUtton.clicked.connect(self.delete)
def add(self):
btncont= self.layout.count()
widget = QPushButton(str(btncont-1), self)
self.layout.addWidget(widget)
def delete(self):
for i in range(self.layout.count())[2:]:
self.layout.itemAt(i).widget().deleteLater()
if __name__ == "__main__":
app = QApplication(sys.argv)
form = DynAddObject()
form.show()
app.exec_()
在动态生成layout与widget的过程中,一开始窗口能够自适应内部的元素,以合适的尺寸显示,但是当窗口被撑大之后无法自动缩小复原。
解决方法:添加一个QTimer以循环执行,在QTimer中使用self.resize(self.sizeHint())
。这个sizeHint()
能够自动给出该widget的建议的尺寸。
对于上面给出的例子,可以修改如下:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
'''pyqt5动态添加删除控件'''
class DynAddObject(QDialog):
def __init__(self, parent=None):
super(DynAddObject, self).__init__(parent)
self.widgetList = []
addButton = QPushButton(u"添加控件")
delBUtton = QPushButton(u"删除控件")
self.layout = QGridLayout()
self.layout.addWidget(addButton, 1, 0)
self.layout.addWidget(delBUtton, 2, 0)
self.setLayout(self.layout)
addButton.clicked.connect(self.add)
delBUtton.clicked.connect(self.delete)
def add(self):
btncont= self.layout.count()
widget = QPushButton(str(btncont-1), self)
self.layout.addWidget(widget)
def delete(self):
for i in range(self.layout.count())[2:]:
self.layout.itemAt(i).widget().deleteLater()
# 在这里设置了timer
self.timer = QTimer(self)
self.timer.timeout.connect(lambda:self.resize(self.sizeHint()))
self.timer.start(1)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = DynAddObject()
form.show()
app.exec_()
在最终的项目中,我使用了60hz的刷新率执行这个timer,其中不仅包含了窗口的resize,还有淡入淡出的动画处理等。
pyqt5带给我的感受尚可,但查询众多资料的过程真的很令人头疼,最后使用pyinstaller
打包的exe达到了臃肿的41MB,其实对于追求简洁美的我来说是不太能够接受的,并且在我的印象中qt的封装结果也是同样臃肿,且丑。万幸的是可以通过setStyleSheet()
稍微挽救一些颜值。
这是我第一次使用pyqt,大概也会是最后一次。在朋友的推荐下,估计今后会在业余时间学习了解一下electron。同时也希望这篇文章能够帮助到一些学习者,祝早日跳出这些坑。
未来我还是比较看好JavaSript/TypeSript。