如何在QPdfView内绘制随PDF文档滚动的矩形?
在QPdfView中绘制随文档滚动的高亮矩形
问题描述
使用Qt 5.15的QPdfView类创建PDF显示控件,需要用矩形高亮PDF中的指定文字,已通过QPdfSearchModel获取到文字的文档坐标系坐标。但继承QPdfView重写paintEvent绘制的矩形固定在视口位置,无法随PDF滚动同步移动。
核心原因
QPdfView继承自QAbstractScrollArea,直接在视口上绘制的坐标是视口本地坐标系,而QPdfSearchModel返回的是PDF文档自身的坐标系矩形,二者未关联缩放比例和滚动偏移,导致矩形位置固定不随文档滚动。
解决方案
需要将文档坐标系中的文字矩形,转换为当前视口的显示坐标系,核心步骤:
- 获取当前视图的缩放因子、滚动偏移量
- 将文档中文字的边界矩形转换为视口坐标
- 仅绘制当前可见区域内的高亮矩形,避免无效渲染
修改后的代码示例
#include <QPdfView> #include <QPdfDocument> #include <QPdfPage> #include <QPainter> #include <QScrollBar> class QPdfViewCustom : public QPdfView { Q_OBJECT public: explicit QPdfViewCustom(QWidget* parent = nullptr) : QPdfView(parent) {} // 设置需要高亮的内容:页面索引 + 文档坐标系矩形 void setHighlightRects(const QList<QPair<int, QRectF>>& rects) { m_highlightRects = rects; viewport()->update(); // 触发视口重绘 } protected: void paintEvent(QPaintEvent *event) override { QPdfView::paintEvent(event); // 先绘制PDF原内容 if (!document()) return; QPainter painter(viewport()); painter.setPen(Qt::red); painter.setBrush(QColor(255, 0, 0, 50)); // 半透明红色高亮,避免遮挡文字 const qreal scale = zoomFactor(); const int vOffset = verticalScrollBar()->value(); const int hOffset = horizontalScrollBar()->value(); for (const auto& item : m_highlightRects) { int pageIdx = item.first; QRectF docRect = item.second; // 获取当前页面在视口的显示区域 QRect pageViewRect = pageViewport(pageIdx); // 只处理当前可见区域内的页面高亮 if (pageViewRect.intersects(event->rect())) { // 转换文档坐标到视口坐标:页面偏移 + 缩放后的矩形尺寸 - 滚动偏移 QRectF viewRect = QRectF( pageViewRect.x() + docRect.x() * scale - hOffset, pageViewRect.y() + docRect.y() * scale - vOffset, docRect.width() * scale, docRect.height() * scale ); painter.drawRect(viewRect); } } } private: QList<QPair<int, QRectF>> m_highlightRects; // 存储高亮内容的页面和矩形信息 };
关键细节说明
pageViewport(pageIdx):获取指定页面在视口上的显示矩形,包含页面的初始位置偏移zoomFactor():将文档坐标系的尺寸转换为视口的实际显示尺寸- 滚动条
value():减去滚动偏移量,确保矩形跟随文档滚动移动 - 可见区域判断:只绘制与当前重绘区域相交的高亮矩形,提升渲染性能
Qt PDF模块说明
Qt PDF模块提供了一套用于查看、渲染PDF文档的类,支持文档导航、文本搜索、缩放显示、页面旋转等核心功能,可快速构建PDF阅读器类应用。
内容的提问来源于stack exchange,提问作者Андрей Петров
相关产品推荐
相关产品推荐

