15

Im trying to do simple audio player, but I want use a image(icon) as a pushbutton.

Alquimista
  • 862
  • 2
  • 10
  • 24

6 Answers6

28

You can subclass QAbstractButton and make a button of your own. Here is a basic simple example:

import sys
from PyQt4.QtGui import *

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

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

    def sizeHint(self):
        return self.pixmap.size()

app = QApplication(sys.argv)
window = QWidget()
layout = QHBoxLayout(window)

button = PicButton(QPixmap("image.png"))
layout.addWidget(button)

window.show()
sys.exit(app.exec_())

That's not a super easy way, but it gives you a lot of control. You can add second pixmap and draw it only when the mouse pointer is hover over button. You can change current stretching behavior to the centering one. You can make it to have not a rectangular shape and so on...

Button that changes images on mouse hover and when pressed:

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class PicButton(QAbstractButton):
    def __init__(self, pixmap, pixmap_hover, pixmap_pressed, parent=None):
        super(PicButton, self).__init__(parent)
        self.pixmap = pixmap
        self.pixmap_hover = pixmap_hover
        self.pixmap_pressed = pixmap_pressed

        self.pressed.connect(self.update)
        self.released.connect(self.update)

    def paintEvent(self, event):
        pix = self.pixmap_hover if self.underMouse() else self.pixmap
        if self.isDown():
            pix = self.pixmap_pressed

        painter = QPainter(self)
        painter.drawPixmap(event.rect(), pix)

    def enterEvent(self, event):
        self.update()

    def leaveEvent(self, event):
        self.update()

    def sizeHint(self):
        return QSize(200, 200)
alex vasi
  • 5,304
  • 28
  • 31
  • 2
    I find this to be the first 'true' solution I've found. Obvious and brilliant. – Anti Earth Oct 30 '12 at 13:51
  • I'm very new to PySide/PyQt and I came across this, which is very useful. But I can't figure out how to add the second pixmap when the button is pressed or when the mouse hovers over. Would it be possible for you to elaborate on that? Thanks. – oxtay Sep 03 '15 at 19:44
  • @oxtay I've updated my answer and added another example. – alex vasi Sep 13 '15 at 09:53
  • Thanks @alexvasi. This was very helpful. This is maybe a whole other question, but is there a way to keep the `pixmap_pressed` as the icon until another button is pressed? Right now, it only changes when mouse is hovering or pressed for a moment but it goes back to normal. I basically want to create the same behavior as active tabs on a browser with almost the same functionality. – oxtay Sep 23 '15 at 18:20
  • @oxtay read about [checkable and checked](http://doc.qt.io/qt-4.8/qabstractbutton.html#checkable-prop) properties. – alex vasi Sep 23 '15 at 20:17
5

You can use QToolButton with set autoraise property true and there you can set your image also.

Achayan
  • 5,720
  • 2
  • 39
  • 61
4

Something like this, maybe?

import sys

from PyQt4.QtGui import *
from PyQt4.QtCore import *

app = QApplication(sys.argv)
widget = QWidget()
layout = QHBoxLayout()
widget.setLayout(layout)
button = QPushButton()
layout.addWidget(button)
icon = QIcon("image.png")
button.setIcon(icon)
widget.show()
app.exec_()
Jesse Aldridge
  • 7,991
  • 9
  • 48
  • 75
4

I've seen that a lot of people have this problem and decided to write a proper example on how to fix it. You can find it here: An example on how to make QLabel clickable The solution in my post solves the problem by extending QLabel so that it emits the clicked() signal. The extended QLabel looks something like this:

class ExtendedQLabel(QLabel):

    def __init__(self, parent):
        QLabel.__init__(self, parent)

    def mouseReleaseEvent(self, ev):
        self.emit(SIGNAL('clicked()'))

I hope this helps!

Ronny Brendel
  • 4,777
  • 5
  • 35
  • 55
MikaelHalen
  • 5,772
  • 1
  • 18
  • 16
  • 4
    The problem with this solution is that a mouse release event is not a click. To be a click the mouse has to got down and up inside the same widget. Otherwise the user may have started to click somewhere else, changed their mind and move the mouse away from the button-they-don't-want-to-click and over this one. Surprise! – Dale Wilson Nov 04 '16 at 14:20
1

Another option is to use stylesheets. Something like:

from PyQt4 import QtCore, QtGui
import os
...

path = os.getcwd()
self.myButton.setStyleSheet("background-image: url(" + path + "/myImage.png);")
swanson
  • 7,377
  • 4
  • 32
  • 34
1

If you want use an image instead of a QPushButton in menubar or in toolbar, you can do it via QAction. Working example:

from PyQt5 import QtWidgets, QtGui, QtCore
import sys

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(MainWindow, self).__init__()
        self.setWindowTitle("Clickable Image in Menubar and Toolbar")

        action = QtWidgets.QAction(
            QtGui.QIcon("image.png"), "&Clickable Image", self)
        action.triggered.connect(self.test)

        menubar = self.menuBar()
        menubar.addAction(action)
        toolbar = QtWidgets.QToolBar("Toolbar")
        toolbar.setIconSize(QtCore.QSize(20, 20))
        toolbar.addAction(action)
        self.addToolBar(toolbar)

    def test(self):

        print("Image clicked.")

app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
lli45
  • 11
  • 2