I'm having a problem updating the icon of a button set with QToolButton
. The idea is to use the button for a movie player. To play, one presses the button and the icon changes to pause. When pressed again, play is paused and the icon reverts to play. I have some working code, but the problem is that the icon is not updating consistently. If I keep the Qt window in focus, it takes one or two button presses to change the icon to the intended image, by which time the actual image is not the intended image (swapped play/pause).
Here is some minimal example code:
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget, QStyle, QToolButton
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
self.play_button = QToolButton(clicked=self.update_button)
self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
self.verticalLayout = QVBoxLayout(self)
self.verticalLayout.addWidget(self.play_button)
self.button_pressed = False
def update_button(self):
if self.button_pressed:
self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
self.button_pressed = False
print("Button should be set to PLAY. Press is", self.button_pressed)
else:
self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
self.button_pressed = True
print("Button should be set to PAUSE. Press is", self.button_pressed)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
In the above I start with a stop icon just to be sure to observe a change (any click should always change the icon). Keeping the window focused, I get the following output:
I've also noticed that if after each click, I click outside the Qt window, or resize the Qt window, the button icon updates to the correct one. What am I doing wrong? How do I force the icon to update?
This behaviour happens mostly with QToolButton
, but QPushButton
also give issues (works when focused, but misbehaves/loses track of correct status if I resize the Qt window). Using PyQt 5.12.3 and qt 5.12.5 on macOS.
Seems like this issue is a bug in the Qt implementation for macOS. I tested and it happens with both PyQt5 and PySide2, so it must come from Qt. Forcing a redraw with a call to .repaint()
after .setIcon()
seems to make the problem go away:
self.play_button.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
self.play_button.repaint()