在 Qt 5.12 中,**对主窗口(如 `QMainWindow` 或 `QWidget`)直接应用 `QTransform` 进行旋转是不被支持的**,原因如下:
- `QTransform` 是用于 **绘图上下文(`QPainter`)** 或 **`QGraphicsItem`** 的坐标变换工具,它本身不能直接作用于顶层窗口(`QWidget`)的几何形态;
- `QWidget`(包括 `QMainWindow`)**不支持通过 `setTransform()` 进行旋转变换** —— `QWidget::setTransform()` 是 **仅限于 `WA_PaintOnScreen` 且非顶层窗口的内部优化机制**,且从 Qt 5.0 起已**标记为 deprecated**,**Qt 5.12 中该函数已被移除或完全无效**(实际调用会触发警告甚至崩溃);
- 真正支持 `QTransform` 的 `setTransform()` 的类是:✅ `QGraphicsItem`、✅ `QPixmap`、✅ `QPainter`(通过 `setTransform()`),❌ `QWidget` / `QMainWindow` 不支持。
---
### ✅ 正确可行的方案(Qt 5.12 兼容)
若你希望实现「主窗口整体旋转效果」(例如 90°/180°/270° 旋转显示),有以下 **3 种主流且稳定的方法**:
---
#### ✅ 方案一:使用 `QGraphicsView` + `QGraphicsScene` + 自定义 `QGraphicsWidget`(推荐,最灵活)
将主窗口内容(如中央部件)包装进 `QGraphicsWidget`,再通过 `QGraphicsView::setTransform()` 控制整个视图旋转。
> ✅ 优点:支持任意角度平滑旋转、缩放、动画;✅ 完全兼容 Qt 5.12;✅ 可保留原 UI 结构逻辑。
##### 示例代码(最小可运行):
```cpp
#include <QApplication>
#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口(仅作为容器)
QMainWindow window;
window.setWindowTitle("Rotated MainWindow (via QGraphicsView)");
// 创建 QGraphicsView 作为 centralWidget
QGraphicsView *view = new QGraphicsView(&window);
QGraphicsScene *scene = new QGraphicsScene(view);
view->setScene(scene);
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setFrameStyle(0);
view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
// 创建一个 QGraphicsWidget 作为“虚拟主窗口内容”
QGraphicsWidget *contentWidget = new QGraphicsWidget();
QVBoxLayout *layout = new QVBoxLayout;
contentWidget->setLayout(layout);
QLabel *label = new QLabel("Hello, Rotated World!");
label->setStyleSheet("font-size: 16px; color: #2c3e50;");
layout->addWidget(new QGraphicsProxyWidget(contentWidget)->setWidget(label));
QPushButton *btn = new QPushButton("Click Me");
layout->addWidget(new QGraphicsProxyWidget(contentWidget)->setWidget(btn));
scene->addItem(contentWidget);
// 🔁 应用旋转:绕中心旋转 30 度(可动态修改)
QTransform transform;
transform.translate(contentWidget->boundingRect().center().x(),
contentWidget->boundingRect().center().y());
transform.rotate(30); // ← 改这里调整角度
transform.translate(-contentWidget->boundingRect().center().x(),
-contentWidget->boundingRect().center().y());
contentWidget->setTransform(transform);
window.setCentralWidget(view);
window.resize(600, 400);
window.show();
return app.exec();
}
```
📌 **关键说明**:
- `QGraphicsWidget` 是 `QGraphicsItem` 的子类,**支持 `setTransform()`**;
- 使用 `QGraphicsProxyWidget` 将普通 `QWidget`(如 `QLabel`, `QPushButton`)嵌入图形场景;
- 旋转以 widget 本地坐标系中心为锚点(需手动 `translate` 实现);
- 若需响应式旋转(如按键切换 0/90/180/270),可封装 `rotate(angle)` 并更新 `setTransform()`。
---
#### ✅ 方案二:使用 `QScreen::setOrientationUpdateMask()` + 屏幕方向(仅适用于嵌入式/平板,需系统支持)
适用于 Linux/X11 或 Android 等平台,通过设置屏幕方向(`Qt::PortraitOrientation` 等)触发系统级旋转:
```cpp
// ⚠️ 注意:仅当 QGuiApplication + 屏幕支持 orientation change 时有效
QScreen *screen = QGuiApplication::primaryScreen();
screen->setOrientationUpdateMask(Qt::PrimaryOrientation | Qt::LandscapeOrientation);
// 然后调用:
screen->setOrientation(Qt::LandscapeOrientation); // 触发整个屏幕旋转
```
> ❗限制:依赖底层平台(Wayland/X11/Android/iOS),桌面 Windows/macOS 通常不支持;且会旋转**所有窗口**,非单窗口可控。
---
#### ✅ 方案三:重写 `paintEvent` + `QPainter::setTransform()`(适合静态旋转,无交互)
若只是「视觉上旋转整个窗口画面」(不响应鼠标事件位置变化),可在自定义 `QWidget` 中重绘:
```cpp
class RotatedWidget : public QWidget {
Q_OBJECT
public:
explicit RotatedWidget(QWidget *parent = nullptr) : QWidget(parent), m_angle(30) {}
protected:
void paintEvent(QPaintEvent *) override {
QPainter p(this);
// 绕窗口中心旋转
QRect r = rect();
p.translate(r.center());
p.rotate(m_angle);
p.translate(-r.center());
// ⚠️ 关键:此时 painter 坐标系已旋转,但子 widget 不自动跟随!
// 所以只能绘制静态内容(如 pixmap、文字、路径等),不能 drawChild() 或 rely on child widgets
p.fillRect(QRect(-r.width()/2, -r.height()/2, r.width(), r.height()), Qt::lightGray);
p.setPen(Qt::black);
p.drawText(-50, 0, "Rotated!");
}
private:
double m_angle;
};
```
> ⚠️ 缺陷:**子 `QWidget` 不会随旋转而重定位/重绘**,鼠标事件坐标也不变 → 实际不可交互,仅作展示用途。
---
### ❌ 错误做法(常见误区)
```cpp
// ❌ 编译可能通过,但运行时无效果或崩溃(Qt 5.12 已移除 QWidget::setTransform)
this->setTransform(QTransform().rotate(45)); // ← 不可用!
// ❌ 试图对 QMainWindow 调用 setTransform(不存在该函数)
static_cast<QMainWindow*>(this)->setTransform(...); // ← 编译失败
```
---
### ✅ 补充建议:若需「整窗口旋转 + 保持控件交互正常」
→ 强烈推荐 **方案一(QGraphicsView)**,并配合:
- `QGraphicsWidget::setGeometry()` 控制布局;
- `QGraphicsItem::mapFromScene()` / `mapToScene()` 处理坐标转换;
- `QPropertyAnimation` 动画旋转:
```cpp
QPropertyAnimation *anim = new QPropertyAnimation(contentWidget, "transform");
anim->setStartValue(QTransform().rotate(0));
anim->setEndValue(QTransform().rotate(90));
anim->setDuration(500);
anim->start();
```
---