用滚动条(scrollbar)控制轴(axis)的范围
虽然最直观的控制axis范围的方法是范围拖动和缩放机制,但可能还需要为此提供scrollbars滚动条。这可以通过signals 和slots 与scrollbar 连接来实现。需要一个中间slot 来在axis的QCPRange和scrollbar 的整数值之间进行转换。
本教程附带的示例项目称为scrollbar-axis-range-control,是完整软件包下载的一部分。
https://www.qcustomplot.com/index.php/tutorials/specialcases/scrollbar
与在滚动条和axis之间来回传播更改相关的信号是QScrollBar::valueChanged(int)和QCPAxis::rangeChanged(QCPRange)。因为我们希望保持正常的拖动和缩放范围,所以当轴的rangeChanged信号发出时,滚动条滑块的位置和大小必须更新。
QScrollBar是基于整数的。因此,我们需要一个因子将整型滚动条值转换为轴坐标。例如,如果我们想要在坐标范围-5到5上平滑滚动坐标轴,我们可以将因子设置为0.01(即将滚动条的值除以100),从而滚动条的范围为-500..500。
ui->horizontalScrollBar->setRange(-500, 500);
ui->verticalScrollBar->setRange(-500, 500);
如果可访问的坐标范围在任何一点发生变化,只需改变滚动条scrollbar的最大值/最小值即可。
执行坐标转换的中间槽称为horzScrollBarChanged、vertScrollBarChanged、xAxisChanged和yAxisChanged。它们连接到滚动条和x-/y轴的适当信号:
connect(ui->horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(horzScrollBarChanged(int)));
connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(vertScrollBarChanged(int)));
connect(ui->plot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange)));
connect(ui->plot->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(yAxisChanged(QCPRange)));
坐标转换slots
这两种类型的slots(轴范围到滚动条 和 滚动条到轴范围)都相当简单。它们分别获取滚动条或轴的更改值,应用转换并将结果设置为轴或滚动条。这些是在移动滚动条滑块时更新轴范围的slots:
void MainWindow::horzScrollBarChanged(int value)
{
if (qAbs(ui->plot->xAxis->range().center()-value/100.0) > 0.01) // if user is dragging plot, we don't want to replot twice
{
ui->plot->xAxis->setRange(value/100.0, ui->plot->xAxis->range().size(), Qt::AlignCenter);
ui->plot->replot();
}
}
void MainWindow::vertScrollBarChanged(int value)
{
if (qAbs(ui->plot->yAxis->range().center()+value/100.0) > 0.01) // if user is dragging plot, we don't want to replot twice
{
ui->plot->yAxis->setRange(-value/100.0, ui->plot->yAxis->range().size(), Qt::AlignCenter);
ui->plot->replot();
}
}
有两件事值得一提:
首先,我们在这里看到通过除以100.0将滚动条值转换为轴坐标。还要注意,当滑块在顶部时,垂直滚动条的值是低的,而当滑块在底部时,垂直滚动条的值是高的。对于绘图轴,情况则相反,这就是为什么要在包含垂直滚动条值的表达式中添加减号,例如在设置yAxis范围时。
条件qAbs(ui->plot->xAxis->range().center()-value/100.0) > 0.01是必要的,这样范围拖动就不会导致由变化信号和槽之间来回导致的双重重画。之所以会出现这种情况,是因为在拖动范围时,QCustomPlot会自动重新对自身进行绘图,并发出拖动轴的范围改变信号。在这个应用程序中,rangeChanged信号将调用插槽xAxisChanged或yAxisChanged,正如我们将看到的,通过调用滚动条的setValue方法更新滚动条滑块的位置。这个方法依次发出与上面的槽连接的滚动条的valueChanged信号。在这里,如果检查没有到位,就会发生第二次重新规划。该检查确保仅当当前轴范围与新的(转换后的)滚动条值不同时才执行重绘图。如果用户拖动轴范围,则不会出现这种情况,因此将跳过冗余的重新绘制和轴范围更新。
在坐标轴范围变化时更新滚动条的槽很简单
void MainWindow::xAxisChanged(QCPRange range)
{
ui->horizontalScrollBar->setValue(qRound(range.center()*100.0)); // adjust position of scroll bar slider
ui->horizontalScrollBar->setPageStep(qRound(range.size()*100.0)); // adjust size of scroll bar slider
}
void MainWindow::yAxisChanged(QCPRange range)
{
ui->verticalScrollBar->setValue(qRound(-range.center()*100.0)); // adjust position of scroll bar slider
ui->verticalScrollBar->setPageStep(qRound(range.size()*100.0)); // adjust size of scroll bar slider
}
他们只是将范围中心转换为滚动条值,并将范围大小转换为滚动条的页面步长(滚动条滑块大小)。