4. 圆形储罐图元与液位动态显示
任务目标
在Qt图形视图框架中,实现图元(QGraphicsItem)的单击选择、框选多选、以及通过Ctrl/Shift键扩展选择,并在选中状态变化时实时更新状态栏信息。本案例将构建一个可独立运行的QGraphicsView应用,支持矩形、圆形、三角形三种图元的交互式选择操作。
环境依赖
仅需Qt 5.12+(含Widgets模块),使用QMake或CMake构建均可。核心依赖为QtWidgets与QtGui模块。
关键完整代码
// main.cpp
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QGraphicsEllipseItem>
#include <QGraphicsPolygonItem>
#include <QStatusBar>
#include <QMainWindow>
#include <QPolygonF>
#include <QPointF>
class SelectableItem : public QGraphicsItem {
public:
SelectableItem(QGraphicsItem* parent = nullptr) : QGraphicsItem(parent) {
setFlags(QGraphicsItem::ItemIsSelectable);
setAcceptHoverEvents(true);
}
QRectF boundingRect() const override { return m_rect; }
void paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) override {
painter->setPen(QPen(Qt::black, 1.5));
if (isSelected()) {
painter->setBrush(QColor(100, 180, 255, 180));
painter->drawRect(boundingRect().adjusted(-3, -3, 3, 3));
} else {
painter->setBrush(QColor(220, 220, 220));
painter->drawRect(boundingRect());
}
}
protected:
QRectF m_rect;
};
class RectItem : public SelectableItem {
public:
RectItem(qreal x, qreal y) {
m_rect = QRectF(x, y, 80, 50);
setPos(x, y);
}
};
class CircleItem : public SelectableItem {
public:
CircleItem(qreal x, qreal y) {
m_rect = QRectF(x, y, 60, 60);
setPos(x, y);
}
void paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) override {
painter->setPen(QPen(Qt::black, 1.5));
if (isSelected()) {
painter->setBrush(QColor(255, 170, 100, 180));
painter->drawEllipse(m_rect.adjusted(-3, -3, 3, 3));
} else {
painter->setBrush(QColor(220, 220, 220));
painter->drawEllipse(m_rect);
}
}
};
class TriangleItem : public SelectableItem {
public:
TriangleItem(qreal x, qreal y) {
m_rect = QRectF(x, y, 70, 60);
setPos(x, y);
}
void paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) override {
QPolygonF tri;
tri << QPointF(m_rect.left(), m_rect.bottom())
<< QPointF(m_rect.center().x(), m_rect.top())
<< QPointF(m_rect.right(), m_rect.bottom());
painter->setPen(QPen(Qt::black, 1.5));
if (isSelected()) {
painter->setBrush(QColor(150, 255, 150, 180));
QPolygonF outer = tri;
// 外扩选中框
QPointF center = m_rect.center();
for (auto& p : outer) {
QPointF d = p - center;
p += d * 0.1;
}
painter->drawPolygon(outer);
} else {
painter->setBrush(QColor(220, 220, 220));
painter->drawPolygon(tri);
}
}
};
class MainWindow : public QMainWindow {
public:
MainWindow() {
QGraphicsScene* scene = new QGraphicsScene(this);
scene->setSceneRect(0, 0, 500, 400);
// 创建图元并添加到场景
scene->addItem(new RectItem(30, 30));
scene->addItem(new CircleItem(180, 50));
scene->addItem(new TriangleItem(320, 30));
scene->addItem(new RectItem(60, 180));
scene->addItem(new CircleItem(250, 200));
scene->addItem(new TriangleItem(380, 180));
QGraphicsView* view = new QGraphicsView(scene, this);
view->setRenderHint(QPainter::Antialiasing);
view->setDragMode(QGraphicsView::RubberBandDrag); // 启用框选
view->setSelectionMode(QGraphicsView::ExtendedSelection); // 支持Ctrl/Shift扩展
setCentralWidget(view);
statusBar()->showMessage("图元数量: 6 | 选中: 0");
// 选中状态变化时更新状态栏
connect(scene, &QGraphicsScene::selectionChanged, this, [this, scene]() {
int count = scene->selectedItems().size();
statusBar()->showMessage(QString("图元数量: %1 | 选中: %2")
.arg(scene->items().size()).arg(count));
});
setWindowTitle("图元选择与多选 - 例4");
resize(600, 450);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}
运行与验证
构建运行:
qmake -project
qmake
make
./your_project_name # Linux/macOS
# Windows下使用对应编译器运行生成的exe
若使用CMake,在CMakeLists.txt中链接Qt5::Widgets即可。
验证步骤与通过条件:
- 单击选择:鼠标左键单击任一图元,该图元出现高亮外框(颜色加深),状态栏显示“选中: 1”。
- 框选多选:在空白处按住左键拖拽,出现橡皮筋矩形框,松开后框内所有图元被选中,状态栏显示对应选中数量。
- 扩展选择:按住
Ctrl键依次单击多个图元,可逐个增加/取消选中;按住Shift键单击可连续扩展选择。 - 取消选择:单击场景空白区域,所有图元取消选中,状态栏显示“选中: 0”。
以上操作均能实时反映在状态栏计数中,且选中图元视觉高亮明显,即判定案例通过。
关键实现说明
- 图元通过设置
ItemIsSelectable标志获得可选中能力,无需额外处理鼠标事件。 - 视图的
RubberBandDrag模式提供框选交互,ExtendedSelection模式启用Ctrl/Shift扩展语义。 - 选中视觉反馈在
paint()中通过isSelected()判断,绘制外扩高亮边框,不依赖系统默认虚线框。 - 状态栏通过
QGraphicsScene::selectionChanged信号实时更新,该信号在任意选中集合变化时触发。