我想要我的 QMessageBox 的动画图标 - 我发现 QtAwesome 有一个漂亮的动画微调器。
所以我尝试了这个非常简单的例子:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
import qtawesome as qta
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Hello World')
self.show()
msgBox = QMessageBox( QMessageBox.NoIcon, "Title", "Content ...", QMessageBox.Cancel )
animation = qta.Spin(msgBox)
spin_icon = qta.icon('fa5s.spinner', color='red', animation=animation)
msgBox.setIcon(spin_icon)
returnValue = msgBox.exec()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
...但是,不幸的是它崩溃了:
$ python3 my_qttest.py
Traceback (most recent call last):
File "C:/msys64/tmp/my_qttest.py", line 23, in <module>
ex = Example()
^^^^^^^^^
File "C:/msys64/tmp/my_qttest.py", line 9, in __init__
self.initUI()
File "C:/msys64/tmp/my_qttest.py", line 18, in initUI
msgBox.setIcon(spin_icon)
TypeError: setIcon(self, a0: QMessageBox.Icon): argument 1 has unexpected type 'QIcon'
嗯,我有点以为
.setIcon
会接受 QIcon 对象,但实际上它不接受 - https://doc.qt.io/qt-5/qmessagebox.html 注意到 QMessageBox::Icon 实际上是一个枚举(不是一堂课,正如我一开始所想的):
Constant Value Description
QMessageBox::NoIcon 0 the message box does not have any icon.
QMessageBox::Question 4 an icon indicating that the message is asking a question.
...
...然而,
qta.icon
返回一个QIcon
。
那么,我如何为 QMessageBox 使用动画 QIcon?
感谢@eyllanesc 的评论:
尝试:
msgBox.setIconPixmap(icon.pixmap())
...我终于成功了:
...虽然它并不像评论所暗示的那么微不足道,所以我将在此答案中发布详细信息:
.pixmap()
方法检索像素图实际上需要一个大小 - 所以我们想要使用最初在 QMessageBox 中使用的像素图大小QMessageBox.NoIcon
,我们将读取0,0的像素图大小,这是不可用的 - 因此我们必须使用其他一些普通的QMessageBox图标进行初始化,以便我们可以检索它们的原始像素图大小setIconPixmap
,也只会显示单个图像,而不是动画 - 要使动画正常工作,我们必须对 QtAwesome Spin
实例的 _update
方法进行猴子修补,并执行 setIconPixmap
从那里总而言之,代码现在是这样的:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
from PyQt5.QtCore import Qt, QPoint, QRect
import qtawesome as qta
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Hello World')
self.show()
msgBox = QMessageBox( QMessageBox.Information, "Title", "Content ...", QMessageBox.Cancel )
msg_newpos_geom = QRect(QPoint(350,350), msgBox.sizeHint())
msgBox.move(msg_newpos_geom.topLeft())
orig_ipmsize = msgBox.iconPixmap().size()
print(orig_ipmsize.width(), orig_ipmsize.height()) # 0 0 for QMessageBox.NoIcon; 32 32 for QMessageBox.Information
animation = qta.Spin(msgBox, autostart=True)
spin_icon = qta.icon('fa5s.spinner', color='red', animation=animation)
# msgBox.setIconPixmap(spin_icon.pixmap(orig_ipmsize)) #msgBox.setIcon(spin_icon) # if this statement is enabled/running here, it prevents new_anim_update from running!
# this is DO_MONKEYPATCH = 1 approach from https://stackoverflow.com/q/78325356 :
old_anim_update = animation._update
def new_anim_update(self):
old_anim_update() # no error
#print("new_anim_update {}".format(self)) # self is <qtawesome.animation.Spin object at 0x00000238f1d45f10>
msgBox.setIconPixmap(spin_icon.pixmap(orig_ipmsize))
animation._update = new_anim_update.__get__(animation, qta.Spin) # https://stackoverflow.com/a/28127947
#print(animation._update)
msgBox.setIconPixmap(spin_icon.pixmap(orig_ipmsize)) #msgBox.setIcon(spin_icon)
#animation.start()
returnValue = msgBox.exec()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())