Search code examples
pythonpython-3.xpyqtpyqt5qt-designer

How to change icon while mouse is clicking in PyQt5


I'm using python 3.6 on PyQt5. I want the button to be off.png by default, then when I'm clicking on it the icon becomes clicking.png, and when I release the click it becomes On.png Currently, it is off.png by default, but clicking on it does not change the icon to clicking.png, and releasing does successfully change the icon to on.png

Strangely enough though, when I'm clicking on the window (instead of the actual button), the icon switches to clicking.png and goes back to off.png once I release it. How can I fix the middle three lines of code so that the icon becomes clicking.png when I'm holding the click on the button, and then become on.png once I release it? Thanks

Note: I don't think the code would run as is if you don't have any of the images saved on your computer.

I've tried messing around with the different modes/states but still couldn't get it to work

self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(160, 180, 271, 121))
self.pushButton.setStyleSheet("")
self.pushButton.setText("")
icon = QtGui.QIcon()

icon.addPixmap(QtGui.QPixmap("images/Clicking.png"))
icon.addPixmap(QtGui.QPixmap("images/Off.png"), QtGui.QIcon.Active)
icon.addPixmap(QtGui.QPixmap("images/On.png"), QtGui.QIcon.Normal, QtGui.QIcon.On)


self.pushButton.setIcon(icon)
self.pushButton.setIconSize(QtCore.QSize(300, 300))
self.pushButton.setCheckable(True)
self.pushButton.setAutoRepeatDelay(400)
self.pushButton.setDefault(False)
self.pushButton.setObjectName("pushButton")

Solution

  • You are confusing the states of the widget with the states of the button with respect to the clicked. In the case of QIcon uses the status of the widget for example the normal state is when the user does not interact with the widget, the selected state is when the user selects the widget, the disabled state is when the widget is disabled, and the active state is when the user interacts with the widget. On the other hand with your logic it is not possible to know the status before the pressed and after the release.

    The solution is to implement a custom button:

    # ...
    
    class PushButton(QtWidgets.QPushButton):
        def __init__(self, parent=None):
            super(PushButton, self).__init__(parent)
            self.setIcon(QtGui.QIcon("images/Off.png"))
    
        def mousePressEvent(self, event):
            super(PushButton, self).mousePressEvent(event)
            self.setIcon(QtGui.QIcon("images/Clicking.png"))
    
        def mouseReleaseEvent(self, event):
            super(PushButton, self).mouseReleaseEvent(event)
            self.setIcon(
                QtGui.QIcon("images/On.png" if self.isChecked() else "images/Off.png")
            )
    
    # ...
    self.pushButton = PushButton(self.centralwidget)
    self.pushButton.setGeometry(QtCore.QRect(160, 180, 271, 121))
    self.pushButton.setStyleSheet("")
    self.pushButton.setText("")
    self.pushButton.setIconSize(QtCore.QSize(300, 300))
    self.pushButton.setCheckable(True)
    self.pushButton.setAutoRepeatDelay(400)
    self.pushButton.setDefault(False)
    self.pushButton.setObjectName("pushButton")
    # ...