QT图形视图系统 - 使用一个项目来学习QT的图形视图框架 - 终篇

QT图形视图系统 - 终篇

接上一篇,我们需要继续完成以下的效果;

先上个效果图:
资源路径:https://download.csdn.net/download/turbolove/88192114?spm=1001.2014.3001.5503

在这里插入图片描述

修改背景,使之整体适配

上一篇我们绘制了标尺,并且我们修改了放大缩小和对应的背景,整体看来,我们的滚动条会和背景不搭配,因此我们需要修改我们的背景,这里使用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中的鼠标修改成十字
展示的是主要代码,并不是全部代码,如果需要全部代码请联系博主获取

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

turbolove

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值