QPainter 中的setWindow与setViewPort

近段时间一直研究,QPainter绘图以及使用QPainter绘制动画;直到今天看到一篇博客中使用QPainter绘图之后,

仅仅只是在绘图前使用了一个setWindow函数就能让图形自适应;于是做了研究。

首先我们不启动以上两个函数,添加如下代码

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
//    painter.setWindow(0,0,300,200); //painter的逻辑绘图区域,左上角为(0,2),右下角为(300,200)
//    painter.setViewport(0,-height() + _y,width(),height()); //实际在窗口映射到窗口显示的区域

    QLinearGradient linGrad1(20, 100, 40, 100);
    linGrad1.setColorAt(0, Qt::gray);
    linGrad1.setColorAt(1, Qt::white);
    linGrad1.setSpread(QGradient::ReflectSpread);
    painter.setBrush(linGrad1);

    QRectF border1(20, 20, 260, 160);
    painter.drawRoundRect(border1, 20, 20);

    painter.setPen(QPen(Qt::black, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
    QRectF border2(25, 25, 250, 150);
    painter.drawRoundRect(border2, 20, 20);
得到的结束如下

QPainter 中的setWindow与setViewPort_第1张图片

如果我们将窗口放大,可以发现图形位置没有变,大小也没有变

QPainter 中的setWindow与setViewPort_第2张图片

修改代码在绘制之前设置painter的逻辑绘图坐标window

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter.setWindow(0,0,300,200); //painter的逻辑绘图区域,左上角为(0,2),右下角为(300,200)
//    painter.setViewport(0,-height() + _y,width(),height()); //实际在窗口映射到窗口显示的区域

    QLinearGradient linGrad1(20, 100, 40, 100);
    linGrad1.setColorAt(0, Qt::gray);
    linGrad1.setColorAt(1, Qt::white);
    linGrad1.setSpread(QGradient::ReflectSpread);
    painter.setBrush(linGrad1);

    QRectF border1(20, 20, 260, 160);
    painter.drawRoundRect(border1, 20, 20);

    painter.setPen(QPen(Qt::black, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
    QRectF border2(25, 25, 250, 150);
    painter.drawRoundRect(border2, 20, 20);
QPainter 中的setWindow与setViewPort_第3张图片
将窗口放大后,可以看见图形在保持比例缩放,就像layOut一样

QPainter 中的setWindow与setViewPort_第4张图片

再修改代码,为painter添加视图区域

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter.setWindow(0,0,300,200); //painter的逻辑绘图区域,左上角为(0,2),右下角为(300,200)
    painter.setViewport(100,50,100,100); //实际在窗口映射到窗口显示的区域

    QLinearGradient linGrad1(20, 100, 40, 100);
    linGrad1.setColorAt(0, Qt::gray);
    linGrad1.setColorAt(1, Qt::white);
    linGrad1.setSpread(QGradient::ReflectSpread);
    painter.setBrush(linGrad1);

    QRectF border1(20, 20, 260, 160);
    painter.drawRoundRect(border1, 20, 20);

    painter.setPen(QPen(Qt::black, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
    QRectF border2(25, 25, 250, 150);
    painter.drawRoundRect(border2, 20, 20);
QPainter 中的setWindow与setViewPort_第5张图片
图形显示在(100,50,100,100)的区域

我们放大窗口

QPainter 中的setWindow与setViewPort_第6张图片


可以发现显示的位置始终在(100,50,100,100)的区域,这所以没有设置时图形能够根具窗口大小自适应,查看文档可知,默认painter的viewPort是与窗口尺寸

相等的;所以这样将逻辑坐标的内容每次都映射到当前窗口就能保证图形自适应了。


查看官方文档可知,painter的默认逻辑区域也是整个窗口区域;这样当我们不去改变逻辑绘图区域和视口时,他们的区域都是窗口区域,这样就形成了我们

常见的画在窗口中的哪个位置就在那个位置显示。而今天的总结,我们可以清楚;其实QPainter画图用的是逻辑坐标(就是自定义左上角坐标和右下角坐标),且

绘图操作都是以逻辑坐标为基准的,当绘图线束后,根据视口区域在窗口中的位置,再把整个绘画结果通过坐标映射全部映射到视口区域(也可以理解为映射因子为逻辑区域

到视口区域的映射转换);注意这里是将整个绘图结果映射,比如绘图时,图形有一部分画在了逻辑区域之外,但通过映射后,如果视口区域名够大能够包映射后的整个图形,

依然是可以显示的,但逻辑区域左上角和右下角映射后的位置一定是视口区域的左上角和右下角


由此,我们在绘制自适应部件时,就方便了,在绘制前设置逻辑坐标区域(固定区域,不要随窗口变化)就可以了,我们在这个固定的逻辑绘图区域先把图画好,再将图

映射到整个窗口(因为默认视口是整个窗口)。窗口尺寸变化时,会自动重绘。

你可能感兴趣的:(Qt)