QT学习教程(二十七)

双缓冲技术(Double Buffering)( 私有函数的实现)

以下是私有函数的实现:

void Plotter::updateRubberBandRegion()
{
QRect rect = rubberBandRect.normalized(); 
update(rect.left(), rect.top(), rect.width(), 1);
 
update(rect.left(), rect.top(), 1, rect.height());
update(rect.left(), rect.bottom(), rect.width(), 1);
update(rect.right(), rect.top(), 1, rect.height());
}

函数updateRubberBand()在mousePressEvent(),mouseMoveEvent()和 mouseReleaseEvent()中被调用,用来删除或者从新绘制橡皮线。函数中调用了四次 update(),用四个绘制事件完成由橡皮线组成的四个小矩形的绘制。Qt 也提供了一个类 QRubberBand 用来绘制橡皮线,但是控件自己提供的绘制函数会更好

void Plotter::refreshPixmap()
{
pixmap = QPixmap(size()); pixmap.fill(this, 0, 0); 
QPainter painter(&pixmap); painter.initFrom(this); 
drawGrid(&painter); 
drawCurves(&painter); 
update();
}

函数refreshPixmap()把plot 绘制到图片上,并且更新控件。首先我们把图片的大小调整为和当前控件大小相同,用控件的背景颜色填充整个图片。这个颜色是当前调色版的“dark”部分。如果背景用的刷子不是固体的(solid brush,刷子的样式,只有颜色,没有花纹的那种最简单的),QPixmap::fill()需要知道控件中刷子的偏移量,以便图片和控件保持一致。因为我们保存的是整个控件,那么因此偏移位置为(0,0)。

在这个函数中,我们使用了一个 QPainter 绘制图片,QPainter::initFrom()设置绘制图片所需画笔,背景和字体,参数this 表示这些设置和Plotter 控件的相应设置是一致的。然后我们调用drawGrid(),drawCurves()绘制网格和曲线。最后,update()函数更新全部控件,在 painteEvent()函数中把图片拷贝到控件上。

void Plotter::drawGrid(QPainter *painter)
{
QRect rect(Margin, Margin,
width() - 2 * Margin, height() - 2 * Margin); 
if (!rect.isValid())
return;
PlotSettings settings = zoomStack[curZoom]; QPen quiteDark = palette().dark().color().light(); QPen light = palette().light().color();
for (int i = 0; i <= settings.numXTicks; ++i) { int x = rect.left() + (i * (rect.width() - 1)
/ settings.numXTicks);
double label = settings.minX + (i * settings.spanX()
/ settings.numXTicks); painter->setPen(quiteDark);
painter->drawLine(x, rect.top(), x, rect.bottom()); painter->setPen(light);
 
painter->drawLine(x, rect.bottom(), x, rect.bottom() + 5); painter->drawText(x - 50, rect.bottom() + 5, 100, 15,
Qt::AlignHCenter | Qt::AlignTop, QString::number(label));
}
for (int j = 0; j <= settings.numYTicks; ++j) { int y = rect.bottom() - (j * (rect.height() - 1)
/ settings.numYTicks);
double label = settings.minY + (j * settings.spanY()
/ settings.numYTicks); painter->setPen(quiteDark);
painter->drawLine(rect.left(), y, rect.right(), y); painter->setPen(light);
painter->drawLine(rect.left() - 5, y, rect.left(), y);
painter->drawText(rect.left() - Margin, y - 10, Margin - 5, 20, Qt::AlignRight | Qt::AlignVCenter, QString::number(label));
}
painter->drawRect(rect.adjusted(0, 0, -1, -1));
}

函数drawGrid()在坐标轴和曲线的下面绘制网格。这个区域由一个矩形确定,如果控件太小,则不绘制。第一个循环绘制网格的垂直线,个数为 x 坐标轴的刻度个数。第二个循环绘制网格的水平线,共y 坐标轴的刻度个数。最后,沿边界绘制一个矩形。drawText()绘制两个坐标轴上刻度的个数。

函数painter->drawText()语法如下:

painter->drawText(x, y, width, height, alignment, text);

其中(x,y,width,height)所确定的矩形确定文字的大小和位置 alignment 为文字的对其方式。

void Plotter::drawCurves(QPainter *painter)
{
static const QColor colorForIds[6] = {
Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow
};
PlotSettings settings = zoomStack[curZoom]; QRect rect(Margin, Margin,
width() - 2 * Margin, height() - 2 * Margin); if (!rect.isValid())
return;
painter->setClipRect(rect.adjusted(+1, +1, -1, -1)); QMapIterator<int, QVector<QPointF> > i(curveMap); while (i.hasNext()) {
i.next();
int id = i.key();
const QVector<QPointF> &data = i.value(); QPolygonF polyline(data.count());
 
for (int j = 0; j < data.count(); ++j) { double dx = data[j].x() - settings.minX; double dy = data[j].y() - settings.minY;
double x = rect.left() + (dx * (rect.width() - 1)
/ settings.spanX());
double y = rect.bottom() - (dy * (rect.height() - 1)
/ settings.spanY()); polyline[j] = QPointF(x, y);
}
painter->setPen(colorForIds[uint(id) % 6]); painter->drawPolyline(polyline);
}
}

函数drawCurves()在网格上绘制出曲线。调用了QPainter::setClipRect()函数设置绘制曲线的矩形区域(不包括四周的间隙和框架)。QPainter 会忽略画到这个区域外的象素。然后我们遍历所有的曲线,在每一条曲线,遍历它所有的 QPointF 点。函数 key()得到曲线的id, value()函数得到曲线的QVector<QPointF>类型的数据。内层循环把QPointF 记录的plotter坐标转换为控件坐标,把它们保存在多段线变量中。转换坐标后,我们设置画笔的颜色(使用函数前面预定义的颜色),调用 drawPolyline()绘制出所有的曲线的点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

随风逐流wrx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值