Search code examples
pythonuser-interfacepyqt4qpainter

How to rotate a QPushButton?


I would like---with Python and Qt4---to rotate a QPushButton (or at least its text) so it can stand vertically. I've seen some documentation online, but I couldn't make much sense out of it---it's in C and I'm C-illiterate.

From what I read though, one needs to re-implement the paintEvent() handler, instantiate and rotate a QPainter(). What I can't figure out however is how to do this for the one QString or QPushButton I need only. I assumed the QPaintEvent would have a "sender" attribute, like signals do, but it hasn't. All I can seem to get from this event is a QRect or QRegion.

How can I find out the event specific to my button or its label?
Or, because that's the question really, how to rotate a QPushButton?

Mru, here below suggested some C++ example, which reimplements the QPushButton completely. Since I have no clue about C++ and since I don't really need a full reimplementation, I've tried to reimplement the painEvent() handler in Python, based on that example.

Here is what I have translated, but it does not work :\

#!/usr/bin/env python


from PyQt4 import QtGui, QtCore
import sys



class RotatedButton(QtGui.QPushButton):
    def __init__(self, text, parent, orientation = "west"):
        QtGui.QPushButton.__init__(self, text, parent)
        self.orientation = orientation

    def paintEvent(self, event):
        painter = QtGui.QStylePainter(self)
        if self.orientation == 'west':
            painter.rotate(90)
        elif self.orientation == 'east':
            painter.rotate(270)
        else:
            raise TypeError
        painter.drawControl(QtGui.QStyle.CE_PushButton, self.getSyleOptions())


    def getSyleOptions(self):

        options = QtGui.QStyleOptionButton()
        options.initFrom(self)        
        size = options.rect.size()
        size.transpose()
        options.rect.setSize(size)
        options.features = QtGui.QStyleOptionButton.None
        options.text = self.text()
        options.icon = self.icon()
        options.iconSize = self.iconSize()
        return options


class Main(QtGui.QFrame):
    def __init__(self):
        QtGui.QFrame.__init__(self)

        self.count = 0
        self.application = QtCore.QCoreApplication.instance()
        self.layout = QtGui.QHBoxLayout()
        self.button = RotatedButton("Hello", self, orientation="west")
        self.layout.addWidget(self.button)
        self.setLayout(self.layout)



if __name__ == '__main__':

    application = QtGui.QApplication(sys.argv)    
    application.main = Main()
    application.main.show()
    sys.exit(application.exec_())

Solution

  • Based on your code:

    #!/usr/bin/env python
    
    from PyQt4 import QtGui, QtCore
    import sys
    
    class RotatedButton(QtGui.QPushButton):
        def __init__(self, text, parent, orientation = "west"):
            super(RotatedButton,self).__init__(text, parent)
            self.orientation = orientation
    
        def paintEvent(self, event):
            painter = QtGui.QStylePainter(self)
            painter.rotate(90)
            painter.translate(0, -1 * self.width());
            painter.drawControl(QtGui.QStyle.CE_PushButton, self.getSyleOptions())
    
        def minimumSizeHint(self):
            size = super(RotatedButton, self).minimumSizeHint()
            size.transpose()
            return size
    
        def sizeHint(self):
            size = super(RotatedButton, self).sizeHint()
            size.transpose()
            return size
    
        def getSyleOptions(self):
            options = QtGui.QStyleOptionButton()
            options.initFrom(self)
            size = options.rect.size()
            size.transpose()
            options.rect.setSize(size)
            options.features = QtGui.QStyleOptionButton.None
            if self.isFlat():
                options.features |= QtGui.QStyleOptionButton.Flat
            if self.menu():
                options.features |= QtGui.QStyleOptionButton.HasMenu
            if self.autoDefault() or self.isDefault():
                options.features |= QtGui.QStyleOptionButton.AutoDefaultButton
            if self.isDefault():
                options.features |= QtGui.QStyleOptionButton.DefaultButton
            if self.isDown() or (self.menu() and self.menu().isVisible()):
                options.state |= QtGui.QStyle.State_Sunken
            if self.isChecked():
                options.state |= QtGui.QStyle.State_On
            if not self.isFlat() and not self.isDown():
                options.state |= QtGui.QStyle.State_Raised
    
            options.text = self.text()
            options.icon = self.icon()
            options.iconSize = self.iconSize()
            return options
    
    
    class Main(QtGui.QFrame):
        def __init__(self):
            QtGui.QFrame.__init__(self)
    
            self.application = QtCore.QCoreApplication.instance()
            self.layout = QtGui.QHBoxLayout()
            self.button = RotatedButton("Hello", self, orientation="west")
            self.layout.addWidget(self.button)
            self.setLayout(self.layout)
    
    if __name__ == '__main__':
    
        application = QtGui.QApplication(sys.argv)
        application.main = Main()
        application.main.show()
        sys.exit(application.exec_())