QT图形视图系统 - 终篇
接上一篇,我们需要继续完成以下的效果;
先上个效果图:
修改背景,使之整体适配
上一篇我们绘制了标尺,并且我们修改了放大缩小和对应的背景,整体看来,我们的滚动条会和背景不搭配,因此我们需要修改我们的背景,这里使用qss修改;并且我们把之前的背景也写到这个里面。
style1.qss
QGraphicsView { background: #000000; } QScrollBar:horizontal { border: none; background: #000000; height: 15px; } QScrollBar::handle:horizontal { background: white; min-width: 20px; } QScrollBar::add-line:horizontal { border: none; background: #000000; width: 0px; } QScrollBar::sub-line:horizontal { border: none; background: #000000; width: 0px; subcontrol-position: left; subcontrol-origin: margin; } /*QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {*/ /* border: 2px solid grey;*/ /* width: 3px;*/ /* height: 3px;*/ /* background: white;*/ /*}*/ QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { background: none; } QScrollBar:vertical { border: none; background: #000000; width: 15px; border-bottom: 1px solid red; } QScrollBar::handle:vertical { background: white; min-height: 20px; } QScrollBar::add-line:vertical { border: none; background: #000000; height: 0px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { border: none; background: #000000; height: 0px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar:up-arrow:vertical, QScrollBar::down-arrow:vertical { border: 2px solid grey; width: 3px; height: 3px; background: white; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; }
然后我们加载这个qss即可, 将之前设置qss的地方修改成读取这个文件
QFile file(":/resources/qss/style1.qss"); file.open(QIODevice::ReadOnly); // 设置软件背景色 setStyleSheet(QString(file.readAll())); file.close();
绘制对应刻度的线条
QGraphicsView有两个函数,一个是绘制背景色,一个是绘制前景色。我们的样条实际上绘制的是背景色,因此我们需要重写这两个函数;
void drawForeground(QPainter* painter, const QRectF& rect) override; void drawBackground(QPainter* painter, const QRectF& rect) override;
去掉之前再scene中添加的文字,我们接下来开始绘制
背景没有什么好说的,直接绘制成黑色的就可以
void GraphicsView::drawBackground(QPainter *painter, const QRectF &rect) { painter->fillRect(rect, Qt::black); // QGraphicsView::drawBackground(painter, rect); }
接下来我们通过前景色来绘制刻度线
constexpr int32_t uScale = 100000; constexpr double dScale = 1.0 / uScale; static std::unordered_map<int, int> gridLinesX, gridLinesY; void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect) { // fixme 这个地方需要修改成按照单位转换的 double scale = pow(10.0, ceil(log10(8.0 / h_ruler_->zoom()))); double lineWidth {0}; gridLinesX.clear(), gridLinesY.clear(); const QColor color[4] { {255, 0, 0, 127}, // 0处使用红色绘制 QColor(100, 100, 100, 50), // Grid1 QColor(100, 100, 100, 150), // Grid5 QColor(100, 100, 100, 255), // Grid10 }; double y, x; draw(scale * 0.1, rect, x, y); draw(scale * 0.5, rect, x, y); draw(scale * 1.0, rect, x, y); gridLinesX[0] = 0; gridLinesY[0] = 0; static QVector<QLineF> lines[4]; for (auto&& vec : lines) vec.clear(); double tmp {}; for (auto [x, colorIndex] : gridLinesX) { tmp = x * dScale; lines[colorIndex].push_back(QLineF(tmp, rect.top(), tmp, rect.bottom())); } for (auto [y, colorIndex] : gridLinesY) { tmp = y * dScale; lines[colorIndex].push_back(QLineF(rect.left(), tmp, rect.right(), tmp)); } painter->save(); painter->setRenderHint(QPainter::Antialiasing, false); int colorIndex {}; for (auto&& vec : lines) { painter->setPen({color[colorIndex++], lineWidth}); painter->drawLines(vec.data(), vec.size()); } auto width { rect.width() }; auto height { rect.height() }; painter->setPen({Qt::yellow, 0.0}); painter->drawLine(QLineF {point_.x() - width, point_.y(), point_.x() + width, point_.y()}); painter->drawLine(QLineF {point_.x(), point_.y() - height, point_.x(), point_.y() + height}); painter->restore(); } void GraphicsView::draw(double sc, const QRectF& rect, double &x, double &y) { if (sc >= 1.0) { int top = floor(rect.top()); int left = floor(rect.left()); y = top - top % int(sc); x = left - left % int(sc); } else { const double k = 1.0 / sc; int top = floor(rect.top()) * k; int left = floor(rect.left()) * k; y = (top - top % int(k)) / k; x = (left - left % int(k)) / k; } for (const auto end_ = rect.bottom(); y < end_; y += sc) ++gridLinesY[ceil(y * uScale)]; for (const auto end_ = rect.right(); x < end_; x += sc) ++gridLinesX[ceil(x * uScale)]; }
这样我们便有了网格线
下面的函数是对ruler和鼠标移动时候的操作
void GraphicsView::updateRuler() { updateSceneRect(QRectF()); // QPoint p = mapFromScene(QPointF()); v_ruler_->setOrigin(p.y()); h_ruler_->setOrigin(p.x()); v_ruler_->setRulerZoom(qAbs(transform().m22() * 0.1)); h_ruler_->setRulerZoom(qAbs(transform().m11() * 0.1)); update(); } void GraphicsView::mouseMoveEvent(QMouseEvent *event) { QGraphicsView::mouseMoveEvent(event); v_ruler_->setCursorPos(event->pos()); h_ruler_->setCursorPos(event->pos()); point_ = mapToScene(event->pos()); emit sig_mouseMove(event->pos()); update(); }
我们之前对鼠标样式进行了修改,这个里面也不要忘记将View中的鼠标修改成十字
展示的是主要代码,并不是全部代码,如果需要全部代码请联系博主获取