创建一个qt c++ 应用程序,使用QGraphicsView 和QGraphicsScene ,, QGraphicsRectItem等,可以打开图片显示, 可以用鼠标在图片上框画ROI, ROI 矩形框可以旋转缩放,移动,拖拽边界大小,给出完整代码程序示例
时间: 2025-03-19 16:11:35 浏览: 33
<think>嗯,用户想要创建一个Qt C++应用程序,使用QGraphicsView、QGraphicsScene和QGraphicsRectItem等组件,能够打开图片显示,并且可以用鼠标在图片上绘制ROI矩形框,支持旋转、缩放、移动和拖拽边界。我需要先理清楚这个需求的各个部分,然后逐步解决。
首先,基本的应用程序结构应该是QMainWindow,包含QGraphicsView和QGraphicsScene。用户需要打开图片,所以需要添加一个QAction来触发文件选择对话框,加载图片作为场景的背景。图片可以用QGraphicsPixmapItem添加到场景中。
接下来是ROI矩形框的功能。普通的QGraphicsRectItem可能无法直接支持旋转、缩放和拖拽,需要自定义一个继承自QGraphicsRectItem的类,并重写一些事件处理函数,比如鼠标按下、移动和释放事件。同时,要处理不同的操作模式,比如移动、旋转、缩放等,可能需要不同的光标和事件处理逻辑。
旋转和缩放通常可以通过设置ItemIsMovable、ItemIsSelectable和ItemSendsGeometryChanges等标志来启用,同时需要重写itemChange函数来响应位置和大小的变化。拖拽边界调整大小可能需要处理鼠标在矩形边缘时的拖拽事件,这时候可能需要判断鼠标的位置是否在边缘附近,然后调整矩形的大小。
另外,旋转功能可能需要通过设置变换来实现,比如使用QTransform的rotate方法。但要注意旋转的中心点,可能需要调整旋转的中心为矩形的中心,而不是默认的左上角。
然后需要考虑用户交互,比如如何切换不同的操作模式。可能需要在自定义的矩形项内部根据光标的位置自动判断是调整大小、旋转还是移动。例如,当光标靠近边缘时显示调整大小的光标,靠近角落时显示旋转光标,内部显示移动光标。这需要重写hoverMoveEvent来检测光标位置并改变光标形状。
对于完整的代码示例,需要包括主窗口的初始化,场景和视图的设置,文件打开的功能,以及自定义矩形项的实现。可能还需要处理场景的缩放,确保图片适应视图的大小,并且在窗口调整时保持比例。
此外,需要注意内存管理,避免内存泄漏。比如,在打开新图片时,需要清除场景中的旧项,并正确释放资源。同时,自定义的矩形项应该管理好自己的事件处理和状态。
可能遇到的问题包括:旋转后的坐标系统变换导致的位置计算错误,调整大小时保持矩形的正确位置和比例,以及多个ROI项之间的交互问题。需要仔细测试每个功能,确保各个操作模式之间的切换顺畅,没有冲突。
最后,确保代码符合Qt的最佳实践,比如使用智能指针管理资源,正确重写事件处理函数,以及保持代码的可读性和可维护性。可能需要参考Qt的官方文档和示例,特别是关于QGraphicsView框架的部分,确保使用正确的方法和属性。</think>以下是一个完整的Qt C++示例,实现带可旋转/缩放/移动的ROI矩形功能:
```cpp
// mainwindow.h
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
class ResizableRectItem : public QGraphicsRectItem {
public:
enum { Type = UserType + 1 };
ResizableRectItem(const QRectF& rect, QGraphicsItem* parent = nullptr);
int type() const override { return Type; }
protected:
void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;
void hoverMoveEvent(QGraphicsSceneHoverEvent* event) override;
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
private:
enum Operation { None, Move, Resize, Rotate };
Operation currentOp = None;
QPointF clickOffset;
double initialRotation = 0;
QPointF initialPos;
};
```
```cpp
// mainwindow.cpp
#include "mainwindow.h"
#include <QGraphicsView>
#include <QFileDialog>
#include <QToolBar>
#include <QTransform>
#include <cmath>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), scene(new QGraphicsScene(this))
{
QGraphicsView* view = new QGraphicsView(scene);
setCentralWidget(view);
QToolBar* toolbar = addToolBar("Tools");
QAction* openAct = toolbar->addAction("打开图片");
connect(openAct, &QAction::triggered, this, &MainWindow::openImage);
}
void MainWindow::openImage()
{
QString path = QFileDialog::getOpenFileName(this, "打开图片");
if(path.isEmpty()) return;
QPixmap pixmap(path);
if(pixmap.isNull()) return;
scene->clear();
scene->addPixmap(pixmap)->setZValue(-1);
scene->setSceneRect(pixmap.rect());
ResizableRectItem* rectItem = new ResizableRectItem(QRectF(100, 100, 200, 150));
rectItem->setFlag(QGraphicsItem::ItemIsSelectable);
rectItem->setFlag(QGraphicsItem::ItemIsMovable);
rectItem->setBrush(QColor(255, 0, 0, 50));
scene->addItem(rectItem);
}
// ResizableRectItem 实现
ResizableRectItem::ResizableRectItem(const QRectF& rect, QGraphicsItem* parent)
: QGraphicsRectItem(rect, parent)
{
setAcceptHoverEvents(true);
setFlags(ItemIsMovable | ItemSendsGeometryChanges);
}
void ResizableRectItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
initialRotation = rotation();
initialPos = pos();
QGraphicsRectItem::mousePressEvent(event);
}
void ResizableRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
if(currentOp == Resize) {
QRectF newRect = rect();
QPointF delta = event->pos() - event->buttonDownPos(Qt::LeftButton);
if(event->modifiers() & Qt::ShiftModifier) {
// 等比缩放
double scale = qMax(delta.x()/rect().width(), delta.y()/rect().height());
newRect.setWidth(rect().width() * (1 + scale));
newRect.setHeight(rect().height() * (1 + scale));
} else {
newRect.setRight(event->pos().x());
newRect.setBottom(event->pos().y());
}
setRect(newRect.normalized());
}
else if(currentOp == Rotate) {
QPointF center = boundingRect().center();
QPointF v1 = event->buttonDownPos(Qt::LeftButton) - center;
QPointF v2 = event->pos() - center;
double angle = atan2(v2.y(), v2.x()) - atan2(v1.y(), v1.x());
setRotation(rotation() + qRadiansToDegrees(angle));
}
else {
QGraphicsRectItem::mouseMoveEvent(event);
}
}
void ResizableRectItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
{
QPointF pos = event->pos();
QRectF r = rect();
// 边缘检测
bool nearEdge = qMin(pos.x(), r.width()-pos.x()) < 5 ||
qMin(pos.y(), r.height()-pos.y()) < 5;
bool nearCorner = (pos.x() < 5 && pos.y() < 5) ||
(pos.x() > r.width()-5 && pos.y() < 5) ||
(pos.x() < 5 && pos.y() > r.height()-5) ||
(pos.x() > r.width()-5 && pos.y() > r.height()-5);
if(nearCorner) {
setCursor(Qt::SizeAllCursor);
currentOp = Rotate;
} else if(nearEdge) {
setCursor(Qt::SizeHorCursor);
currentOp = Resize;
} else {
setCursor(Qt::OpenHandCursor);
currentOp = Move;
}
}
QVariant ResizableRectItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
if(change == ItemPositionChange && scene()) {
// 限制移动范围在场景内
QPointF newPos = value.toPointF();
QRectF sceneRect = scene()->sceneRect();
if(!sceneRect.contains(newPos + rect().center())) {
newPos.setX(qBound(sceneRect.left()-rect().width()/2, newPos.x(),
sceneRect.right()-rect().width()/2));
newPos.setY(qBound(sceneRect.top()-rect().height()/2, newPos.y(),
sceneRect.bottom()-rect().height()/2));
return newPos;
}
}
return QGraphicsItem::itemChange(change, value);
}
```
```cpp
// main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
```
关键特性说明:
1. 图片加载功能
- 通过`QFileDialog`选择图片
- 使用`QGraphicsPixmapItem`显示图片
- 自动设置场景范围
2. ROI矩形功能
- 支持鼠标拖拽移动
- 边缘拖拽调整大小(按住Shift等比缩放)
- 角落拖拽旋转
- 自动光标切换(移动↔︎缩放↔︎旋转)
- 移动范围限制在场景内
3. 使用说明
- 编译运行后点击工具栏"打开图片"
- 红色半透明矩形即为ROI区域
- 边缘拖拽调整大小
- 角落拖拽旋转
- 中心区域拖拽移动
扩展建议:
1. 添加多个ROI支持
2. 增加坐标显示功能
3. 添加序列化保存/加载ROI数据
4. 实现更精确的碰撞检测
5. 添加缩放视图功能(使用`QGraphicsView::setTransformationAnchor`)
请确保.pro文件包含以下配置:
```qmake
QT += widgets
SOURCES += main.cpp mainwindow.cpp
HEADERS += mainwindow.h
```
阅读全文
相关推荐


















