前文链接:Qt实现思维导图功能5『纵向分布模式』
百度网盘体验地址:
链接:https://pan.baidu.com/s/1xotlkSPfG7E_37y_XPfDng
提取码:5li7
效果图
1、动态演示效果:
思维导图-鹰眼视图
2、静态展示图片:
新增功能如下
序号 | 简述 | 具体功能 |
---|---|---|
1 | 显示全场景 | 保持场景纵横比不变的情况下最大化显示全场景导图信息 |
1 | 矩形导航框 | 显示场景具体大小,随主视图缩放/移动而变化 |
1 | 视野跳转 | 鹰眼视图支持鼠标点击后立即跳转到指定位置,该位置将呈现在主视图视野中心 |
1 | 视野移动 | 鹰眼视图支持鼠标移动时触发主视图视野伴随移动,移动过程丝滑无卡顿 |
新增UI如下
序号 | 简述 | 具体功能 |
---|---|---|
1 | 鹰眼视图窗口 | 显示和操控主视图中场景图元位置 |
核心代码
#pragma once
/*
* 鹰眼视图窗口
* 1、最大化显示全场景图元
* 2、矩形导航框自适应场景缩放与移动
*/
#include <QWidget>
#include "ui_EagleWidget.h"
class QGraphicsView;
class QGraphicsPixmapItem;
class QGraphicsRectItem;
class EagleWidget : public QWidget
{
Q_OBJECT
public:
EagleWidget(QWidget *parent = nullptr);
~EagleWidget();
// 设置主视图
void setMainView(QGraphicsView *view);
protected:
bool eventFilter(QObject *watched, QEvent *event);
private slots:
void on_btnClose_clicked();
private:
Ui::EagleWidget ui;
QGraphicsView *m_mainView; // 主视图
QGraphicsPixmapItem *m_bgPixmapItem; // 背景图元
QGraphicsRectItem *m_rectItem; // 矩形导航框
};
#include "EagleWidget.h"
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QGraphicsRectItem>
#include <QMouseEvent>
EagleWidget::EagleWidget(QWidget *parent /*= nullptr*/)
: QWidget(parent)
, m_mainView(nullptr)
{
ui.setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
m_bgPixmapItem = new QGraphicsPixmapItem();
m_rectItem = new QGraphicsRectItem;
m_rectItem->setPen(QPen(Qt::red));
ui.graphicsView->setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing);
ui.graphicsView->viewport()->installEventFilter(this);
ui.graphicsView->setCursor(QCursor(Qt::CrossCursor));
}
EagleWidget::~EagleWidget()
{
}
void EagleWidget::setMainView(QGraphicsView *view)
{
m_mainView = view;
m_mainView->installEventFilter(this);
m_mainView->viewport()->installEventFilter(this);
QGraphicsScene *scene = new QGraphicsScene(ui.graphicsView->viewport()->rect());
ui.graphicsView->setScene(scene);
scene->setBackgroundBrush(m_mainView->scene()->backgroundBrush());
scene->addItem(m_bgPixmapItem);
scene->addItem(m_rectItem);
}
bool EagleWidget::eventFilter(QObject *watched, QEvent *event)
{
if (m_mainView == nullptr)
return QWidget::eventFilter(watched, event);
if (watched == m_mainView)
{
if (event->type() == QEvent::Paint || event->type() == QEvent::Wheel)
{
QGraphicsScene *scene = m_mainView->scene();
// 设置图像大小与场景图元边界大小一致
QRectF itemsBoundingRect = scene->itemsBoundingRect();
QPixmap pixmap(itemsBoundingRect.width(), itemsBoundingRect.height());
// 渲染图像
QPainter painter;
painter.begin(&pixmap);
painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing);
scene->render(&painter, pixmap.rect(), itemsBoundingRect);
painter.end();
// 调整图像大小
QSize eagleViewportSize = ui.graphicsView->viewport()->rect().size();
QPixmap scaledPixmap = pixmap.scaled(eagleViewportSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_bgPixmapItem->setPixmap(scaledPixmap);
// 调整图像位置
if (scaledPixmap.height() <= ui.graphicsView->viewport()->height())
m_bgPixmapItem->setY((ui.graphicsView->viewport()->height() - scaledPixmap.height()) / 2.0);
if (scaledPixmap.width() <= ui.graphicsView->viewport()->width())
m_bgPixmapItem->setX((ui.graphicsView->viewport()->width() - scaledPixmap.width()) / 2.0);
// 计算缩放后的图元大小与主视窗大小的水平/垂直比率
QRectF bgPixmapRect = m_bgPixmapItem->boundingRect();
QSize mainViewportSize = m_mainView->viewport()->rect().size();
qreal scaleFactor = m_mainView->matrix().m11();
double scaleH = itemsBoundingRect.width() * scaleFactor / mainViewportSize.width();
double scaleV = itemsBoundingRect.height() * scaleFactor / mainViewportSize.height();
double scaleMax = qMax(scaleH, scaleV);
if (scaleMax <= 1)
{// 当比率<=1时,矩形导航框为整个鹰眼视图中的背景图元大小
m_rectItem->setRect(bgPixmapRect);
m_rectItem->setPos(m_bgPixmapItem->pos());
}
else// scaleMax > 1
{// 当比率>1时,矩形导航框为主视窗中图元占整个场景图元的比率所对应的鹰眼视图大小
QPointF viewportTopLeftToScenePos = m_mainView->mapToScene(QPoint(0, 0));
double offsetXRatio = (viewportTopLeftToScenePos.x() - itemsBoundingRect.x()) / itemsBoundingRect.width();
double offsetYRatio = (viewportTopLeftToScenePos.y() - itemsBoundingRect.y()) / itemsBoundingRect.height();
m_rectItem->setRect(0, 0, bgPixmapRect.width() / scaleH, bgPixmapRect.height() / scaleV);
m_rectItem->setPos(offsetXRatio * bgPixmapRect.width() + m_bgPixmapItem->x(), offsetYRatio * bgPixmapRect.height() + m_bgPixmapItem->y());
}
// 显示缩放比率
if (scaleMax != 0)
ui.lblScale->setText(QString("%1%").arg((int)(scaleMax * 100)));
}
}
else if (watched == m_mainView->viewport())
{
if (event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *>(event);
if (mouseEvent->buttons() != Qt::LeftButton)
return QWidget::eventFilter(watched, event);
QGraphicsScene *scene = m_mainView->scene();
QRectF itemsBoundingRect = scene->itemsBoundingRect();
// 计算缩放后的图元大小与主视窗大小的水平/垂直比率
QRectF bgPixmapRect = m_bgPixmapItem->boundingRect();
QSize mainViewportSize = m_mainView->viewport()->rect().size();
qreal scaleFactor = m_mainView->matrix().m11();
double scaleH = itemsBoundingRect.width() * scaleFactor / mainViewportSize.width();
double scaleV = itemsBoundingRect.height() * scaleFactor / mainViewportSize.height();
double scaleMax = qMax(scaleH, scaleV);
if (scaleMax > 1)
{// 当比率>1时,矩形导航框为主视窗中图元占整个场景图元的比率所对应的鹰眼视图大小
QPointF viewportTopLeftToScenePos = m_mainView->mapToScene(QPoint(0, 0));
double offsetXRatio = (viewportTopLeftToScenePos.x() - itemsBoundingRect.x()) / itemsBoundingRect.width();
double offsetYRatio = (viewportTopLeftToScenePos.y() - itemsBoundingRect.y()) / itemsBoundingRect.height();
m_rectItem->setRect(0, 0, bgPixmapRect.width() / scaleH, bgPixmapRect.height() / scaleV);
m_rectItem->setPos(offsetXRatio * bgPixmapRect.width() + m_bgPixmapItem->x(), offsetYRatio * bgPixmapRect.height() + m_bgPixmapItem->y());
}
}
}
else if (watched == ui.graphicsView->viewport())
{
if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *>(event);
QRectF bgPixmapRect = m_bgPixmapItem->boundingRect();
QGraphicsScene *scene = m_mainView->scene();
QRectF itemsBoundingRect = scene->itemsBoundingRect();
// 换算鼠标点击处在场景中的位置,并将该位置设置为视野中心
double offsetX = mouseEvent->x() - m_bgPixmapItem->x();
double offsetY = mouseEvent->y() - m_bgPixmapItem->y();
double scale = bgPixmapRect.width() / itemsBoundingRect.width();
double sceneOffsetX = itemsBoundingRect.x() + offsetX / scale;
double sceneOffsetY = itemsBoundingRect.y() + offsetY / scale;
m_mainView->centerOn(sceneOffsetX, sceneOffsetY);
// 计算缩放后的图元大小与主视窗大小的水平/垂直比率
QSize mainViewportSize = m_mainView->viewport()->rect().size();
qreal scaleFactor = m_mainView->matrix().m11();
double scaleH = itemsBoundingRect.width() * scaleFactor / mainViewportSize.width();
double scaleV = itemsBoundingRect.height() * scaleFactor / mainViewportSize.height();
double scaleMax = qMax(scaleH, scaleV);
if (scaleMax > 1)
{// 当比率>1时,设置矩形导航框位置
QPointF scenePos = ui.graphicsView->mapToScene(mouseEvent->pos());
m_rectItem->setPos(scenePos.x() - m_rectItem->rect().width() / 2, scenePos.y() - m_rectItem->rect().height() / 2);
}
}
}
return QWidget::eventFilter(watched, event);
}
void EagleWidget::on_btnClose_clicked()
{
close();
}