在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
,但我们预料到了这一点并且它已在代码中处理。虽然我不希望它显示,但我无法想出任何方法来阻止它。
我需要旋转 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
,但我们预料到了这一点并且它已在代码中处理。虽然我不希望它显示,但我无法想出任何方法来阻止它。