在Qt中旋转某些QWidgets

Rotate Certain QWidgets in Qt

我需要旋转 UI 的某些元素(不是全部)。我已经尝试了一些东西,其中 none 提供了我需要的解决方案。

我尝试使用 QGraphicsProxyWidget 和图形视图,如果我想旋转整个 UI,这很有效,但无法仅旋转某些元素。

我试图将小部件提升为覆盖 paintEvent 的自定义 class。我无法通过这种方式工作。以下是我目前的代码

#include <QPushButton>
#include <QPainter>
#include <QPaintEvent>    

class QRotateButton : public QPushButton
{
    Q_OBJECT
public:
    QRotateButton (QWidget *parent = 0) {}

protected:
    void paintEvent(QPaintEvent *event) override {
        if (isDrawing)
            return QRotateButton::paintEvent(event);

        isDrawing = true;
        QPixmap buttonPixmap = grab();
        QPainter painter(this);
        painter.rotate(90);
        painter.drawPixmap(0, 0, height(), width(), buttonPixmap);
        isDrawing = false;
    }
private:
    bool isDrawing = false;
};

此returns以下错误

QWidget::repaint: Recursive repaint detected
Segmentation fault

提前致谢

更新

根据下面的评论,我将代码更改为调用 QPushButton::paintEvent(Event) 而不是 QRotateButton::paintEvent(Event)

应用程序现在可以打开,而以前没有。但不幸的是没有显示按钮。现在每当调用 paintEvent 时,控制台中都会出现以下错误消息:

QWidget::repaint: Recursive repaint detected
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::rotate: Painter not active

在进一步研究之后,我设法弄明白了。

#include <QPushButton>
#include <QPainter>
#include <QPaintEvent>

class QRotateButton : public QPushButton
{
    Q_OBJECT
public:    
    QRotateButton (QWidget *) {        
        //Set variables to defaults
        _isDrawing = false;
        _recursiveCounter = 0;
        _recursiveMax = 1;
        _rotationSetting = 0;
        _rotationAngle = 0;
        _rotationX = 0;
        _rotationY = 0;
        _rotationWidth = 0;
        _rotationHeight = 0;
    }

    /* Set rotation setting */
    void SetRotation(int setting) {
        //Set rotation setting
        _rotationSetting = setting;

        //Call paintEvent
        this->update();
    }


protected:
    void paintEvent(QPaintEvent *event) override {        
        //If its drawing then it just wants to do the normal paintEvent
        if (_isDrawing)
        {
            QPushButton::paintEvent(event);
            return;
        }       

        //Setup the variables depending on setting
        setupRotationVariables();       

        //Setup painter and rotate to angle
        QPainter painter(this);
        painter.rotate(_rotationAngle);

        //Without this here, this function is called over and over,
        //this stops that whilst maintaing the rotated image we want
        if (_recursiveCounter > 0 && _requiresRotation)
        {
            _recursiveCounter--;
            painter.drawPixmap(_rotationX, _rotationY, _drawing.width(), _drawing.height(), _drawing);            
            return;
        }


        //When rotating 90/270 degrees, we resize the image so that we don't stretch the image
        //This is not required when flipping the image
        if (_requiresRotation)                    
            resize(_rotationWidth, _rotationHeight);



        //Get the button image, this will call this function so we set _isDrawing to true whilst it's going on so meaning that it's does the base method and returns
        _isDrawing = true;
        _drawing = grab();
        _isDrawing = false;

        //Now we have the image, if rotation is being done resize the widget back to it's previous measurements
        if (_requiresRotation)                   
            resize(_rotationHeight, _rotationWidth);

        //Draw the image to the picture
        painter.drawPixmap(_rotationX, _rotationY, _drawing.width(), _drawing.height(), _drawing);

        //Depending on if this has rotated or not, setup the catch the tailend of the rotation event
        if (_requiresRotation)
            _recursiveCounter = _recursiveMax;
        else
            _recursiveCounter = 0;
    }

private:
    /* Stops Recursive resizing when resizing is required */
    int _recursiveCounter;
    int _recursiveMax;

    /* If the widget is currently drawing, stops certain recursive calls */
    bool _isDrawing;    

    /* If the widget needs to rotated instead of flipped */
    bool _requiresRotation;

    /* Contains image of previous render of button, for use in recursive calls */
    QPixmap _drawing;

    /* Rotation Setting (0-3) defines rotation type. This is used since rotations should only be multiples of 90 */
    int _rotationSetting;

    /* Variables after rotation */
    int _rotationAngle;
    int _rotationX;
    int _rotationY;
    int _rotationWidth;
    int _rotationHeight;

    /* Fetch variables based on Rotation Setting */
    void setupRotationVariables () {
        //Figure out what rotation is required
        switch (_rotationSetting)
        {
        case 0: //Up side up
            _rotationAngle = 0;
            _rotationWidth = width();
            _rotationHeight = height();
            _rotationX = 0;
            _rotationY = 0;
            _requiresRotation = false;
            break;
        case 1: //Right side up
            _rotationAngle = 90;
            _rotationWidth = height();
            _rotationHeight = width();
            _rotationX = 0;
            _rotationY = -width();
            _requiresRotation = true;
            break;
        case 2: //Down side up
            _rotationAngle = 180;
            _rotationWidth = width();
            _rotationHeight = height();
            _rotationX = -width();
            _rotationY = -height();
            _requiresRotation = false;
            break;
        case 3: //Left side up
            _rotationAngle = 270;
            _rotationWidth = height();
            _rotationHeight = width();
            _rotationX = -height();
            _rotationY = 0;
            _requiresRotation = true;
            break;
        default:
            printf("INVALID ROTATION\n");
            break;
        }
    }

};

备注

每次调用 paintEvent 时仍会抛出 QWidget::repaint: Recursive repaint detected,但我们预料到了这一点并且它已在代码中处理。虽然我不希望它显示,但我无法想出任何方法来阻止它。