0

I'm very new to PySide/PyQt environment. I'm trying to make a menu of buttons on top and assign a task to each so that when they are clicked a function draws a painting on the central window. But I also want to make the button change when they are clicked.

I think this might be an straighforward problem to solve if I use QPushButton, but my buttons are images and I'm using the method suggested HERE and use QAbstractButton to create them.

It is mentioned there that

You can add second pixmap and draw it only when the mouse pointer is hover over button.

And I'm trying to do exactly that. My question is this:

what are possible ways to achieve this? Are the same methods in QPushButtons applicable here? If so, are there any examples of it somewhere?

Here is a snippet of my code:

import sys
from PySide import QtGui, QtCore

BACKGROUND_COLOR = '#808080'
ICON_PATH_ACTIVE = 'icons/activ'
ICON_PATH_PASSIVE = 'icons/pasiv'

class MainWindow(QtGui.QMainWindow):

    def __init__(self, app=None):
        super(MainWindow, self).__init__()
        self.initUI()

    def initUI(self):

        dockwidget = QtGui.QWidget()

        self.setGeometry(200, 200, 400, 300)

        hbox = QtGui.QHBoxLayout()

        1_button = PicButton(QtGui.QPixmap("icons/pasiv/1.png"))
        2_button = PicButton(QtGui.QPixmap("icons/pasiv/2.png"))
        3_button = PicButton(QtGui.QPixmap("icons/pasiv/3.png"))

        hbox.addWidget(1_button)
        hbox.addWidget(2_button)
        hbox.addWidget(3_button)

        vbox = QtGui.QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.setAlignment(hbox, QtCore.Qt.AlignTop)

        dockwidget.setLayout(vbox)

        self.setCentralWidget(dockwidget)   

class PicButton(QtGui.QAbstractButton):
    def __init__(self, pixmap, parent=None):
        super(PicButton, self).__init__(parent)
        self.pixmap = pixmap
        self.setFixedSize(100, 100)

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.drawPixmap(event.rect(), self.pixmap)

def main():

    app = QtGui.QApplication(sys.argv)

    central = MainWindow()
    central.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Thank you.

Community
  • 1
  • 1
oxtay
  • 3,990
  • 6
  • 30
  • 43

1 Answers1

1

Use a regular QPushButton with an icon.

iplay = QtGui.QIcon("path/play_icon.png")
ipause = QtGui.QIcon("path/pause_icon.png")
btn = QtGui.QPushButton(ipause, "", None)

def toggle_play():
    if btn.icon() == ipause:
        btn.setIcon(iplay)
        # Do Pause Action
    else:
        btn.setIcon(ipause)
        # Do Play Action
btn.clicked.connect(toggle_play)
btn.show()

If you want hover functionality then you will have to subclass the QPushButton

class MyButton(QtGui.QPushButton):

    custom_click_signal = QtCore.Signal()

    def enterEvent(self, event):
        super().enterEvent(event)
        # Change icon hove image here

    def leaveEvent(self, event):
        super().leaveEvent(event)
        # Change icon back to original image here.

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        self.custom_click_signal.emit()
        # connect to signal btn.custom_click_signal.connect(method)

Icons are probably the easiest way instead of manually managing the paint event. There are also mousePressEvent and mouseReleaseEvents if you want the icon to change for someone holding the button down.

justengel
  • 6,132
  • 4
  • 26
  • 42
  • Is there a way to do it with my current code, using QAbstractButton instead of QPushButton? – oxtay Sep 03 '15 at 21:31
  • managing the paintEvent is not a fun thing to do. You can do it by using the mousePressEvent, but you would have to manually program in the haptic feedback (The look of the button being pressed). Other wise the user just clicks an image and doesn't know if it is doing anything. The button wont appear to go down and be pressed. – justengel Sep 03 '15 at 21:34
  • Thanks. I'll give it a try now. – oxtay Sep 03 '15 at 21:41
  • So I tried it. Now I realize what the problem with using PushButton might be. I resized the button but the image is now not the button itself but part of the button. Adding `setIconSize` and `setFixedSize` worked. Thanks for the tips. It was very helpful. But now, if I cover the entire button with my icon, it still won't be clear if the button is being clicked or not. I'm thinking of adding a resize function that would make the icon a couple of pixels smaller when clicked to give the impression of getting clicked. – oxtay Sep 04 '15 at 19:40
  • I was wondering if there is a way to create a functionality similar to browser tabs so that unless another button is pressed, the `hove image` stays as the icon for the button? – oxtay Sep 23 '15 at 18:22
  • http://pyside.github.io/docs/pyside/PySide/QtGui/QMouseEvent.html There is a button within the event for mouse events. http://pyside.github.io/docs/pyside/PySide/QtCore/Qt.html has a list of Qt.MouseButton's. So you can detect what button created the mousePressEvent which should help with what you want. – justengel Sep 23 '15 at 19:22