Qt由入门到放弃-QCustomPlot绘制天气曲线图并动态显示曲线坐标值(二)
由于项目需要,实现天气预报的曲线绘制功能,进而学习了QCustomPlot的第三方控件,这里浅尝辄止的分享一下自己对QCPAxisTicker坐标轴类的使用,先上图看QCPAxisTicker的几种用法:
QCPAxisTicker是坐标轴的基类,它的属性和方法如下,其中有刻度轴步长显示策略TickStepStrategy的枚举类型,可参考此篇文章QCustomplot使用分享(六) 坐标轴和网格线:
class QCPAxisTicker
{
public:
/*!
定义选择坐标轴步长策略
*/
enum TickStepStrategy
{
tssReadability //具有更好可读性的(由系统分配)刻度步长匹配优先于自定义分配刻度数目匹配
,tssMeetTickCount //使用setTickCount()函数设置用户自定义的刻度数目
};
// getters:
TickStepStrategy tickStepStrategy() const { return mTickStepStrategy; }//获得刻度匹配策略
int tickCount() const { return mTickCount; }//返回刻度数
double tickOrigin() const { return mTickOrigin; }//获得起点坐标偏移量
// setters:
void setTickStepStrategy(TickStepStrategy strategy);//设置刻度匹配策略
void setTickCount(int count);//设置刻度数目
void setTickOrigin(double origin);//设置起点坐标偏移量
// introduced virtual methods:虚函数自定义生成坐标刻度
virtua void generate(const QCPRange &range, const QLocale &locale, QChar formatChar,
int precision, QVector &ticks, QVector *subTicks, QVector *tickLabels);
protected:
// property members:
TickStepStrategy mTickStepStrategy;
int mTickCount;
double mTickOrigin;
// introduced virtual methods:
virtual double getTickStep(const QCPRange &range);//获得轴范围内刻度间距
virtual int getSubTickCount(double tickStep);//一个大刻度间距中子刻度的数目
virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision);//获得刻度向量
virtual QVector createTickVector(double tickStep, const QCPRange &range);//生成刻度向量
virtual QVector createSubTickVector(int subTickCount, const QVector &ticks);//生成子刻度向量
//生成刻度标签向量
virtual QVector createLabelVector(const QVector &ticks,
const QLocale &locale, QChar formatChar, int precision);
// non-virtual methods:
//trimTicks()从指定范围之外的刻中移除刻度坐标,如果keepOneOutlier==true,则在保留的刻度范围两边保留刻度标记
void trimTicks(const QCPRange &range, QVector &ticks, bool keepOneOutlier) const;
//pickClosest()返回包含在与所提供的目标最接近的候选坐标,此方法假定候选者不是空的,按升序排序
double pickClosest(double target, const QVector &candidates) const;
//getMantissa()返回输入的十进制尾数,例如142.6的输入将返回尾数1.426和100的大小。
double getMantissa(double input, double *magnitude=0) const;
//cleanMantissa()返回一个接近输入的数字,它有一个更简单的人类可读尾数
double cleanMantissa(double input) const;
};
关于日期时间可看我前一篇Qt由入门到放弃-QDate、QTime、QDateTime的相关函数,具体方法如下所示:
class QCPAxisTickerDateTime : public QCPAxisTicker
{
public:
// getters:
QString dateTimeFormat();//获得日期显示格式
Qt::TimeSpec dateTimeSpec();//获得时区
// setters:
void setDateTimeFormat(const QString &format);//设置时间显示格式
void setDateTimeSpec(Qt::TimeSpec spec);//设置时区
void setTickOrigin(double origin);
void setTickOrigin(const QDateTime &origin);
// static methods:
static QDateTime keyToDateTime(double key);//时间戳转成日期
static double dateTimeToKey(const QDateTime dateTime);//日期转成时间戳秒
static double dateTimeToKey(const QDate date);//日期转成时间戳秒
protected:
// property members:
QString mDateTimeFormat;//格式化时间
Qt::TimeSpec mDateTimeSpec;//时区
// non-property members:
enum DateStrategy //设置刻度策略
{
dsNone //刻度不设置间距,默认大于等于一秒
, dsUniformTimeInDay //刻度间距大于等于一天
, dsUniformDayInMonth //刻度间距大于等于一月
} mDateStrategy;
// reimplemented virtual methods:
virtual double getTickStep(const QCPRange &range);
virtual int getSubTickCount(double tickStep) ;
virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) ;
virtual QVector createTickVector(double tickStep, const QCPRange &range) ;
};
void setupTestQCPAxisTickerDateTime()
{
customPlot->setInteraction(QCP::iRangeDrag, true);
customPlot->setInteraction(QCP::iRangeZoom, true);
QDateTime dateTime = QDateTime::currentDateTime();
double now = dateTime.toTime_t();//当前时间转化为秒
//生成时间刻度对象
QSharedPointer dateTimeTicker(new QCPAxisTickerDateTime);
customPlot->xAxis->setTicker(dateTimeTicker);
//dateTimeTicker->setDateTimeSpec(Qt::UTC);//设施世界时间,即不加上时区的时间
dateTimeTicker->setTickCount(12);
dateTimeTicker->setTickStepStrategy(QCPAxisTicker::tssMeetTickCount);
customPlot->xAxis->setSubTicks(false);
customPlot->xAxis->setRange(now, now+3600*24);//x轴范围,从当前时间起往后推24小时
QVector yData, xData;//生成数据
for (int i = 0; i <= 24; i++)
{
xData.push_back(now + i * 3600.0);
yData.push_back(pow(double(i), 2) + 550.0*sin(double(i)/4.0));
}
dateTimeTicker->setDateTimeFormat("yyyy-M-d h:m");//设置x轴刻度显示格式
customPlot->xAxis->setTickLabelRotation(30);//设置刻度标签顺时针旋转30度
customPlot->yAxis->setRange(-1000,10000);
customPlot->addGraph();
customPlot->graph(0)->setData(xData, yData);//显示数据
}
QCPAxisTickerDateTime坐标轴默认是从时间戳起点即1970-1-1 0:0:0开始,以秒为单位进行刻度划分, 以下前两行代码为核心,获取当前秒数,通过第三行代码来设置时间范围。
QDateTime dateTime = QDateTime::currentDateTime();
double now = dateTime.toTime_t();//当前时间转化为秒
customPlot->xAxis->setRange(now, now+3600*24);//x轴范围,从当前时间起往后推24小时
class QCPAxisTickerTime : public QCPAxisTicker
{
public:
enum TimeUnit { tuMilliseconds ///< 毫秒(%z 在setTimeFormat中设置)
,tuSeconds ///< 秒 (%s)
,tuMinutes ///< 分钟 (%m)
,tuHours ///< 小时 (%h)
,tuDays ///< 天 (%d)
};
// getters:
QString timeFormat();//获得时间显示格式
int fieldWidth(TimeUnit unit) const { return mFieldWidth.value(unit); }
// setters:
void setTimeFormat(const QString &format);
void setFieldWidth(TimeUnit unit, int width);//设置刻度间距宽度
protected:
// property members:
QString mTimeFormat;//时间格式化字符串
QHash mFieldWidth;//时间宽度格式
// non-property members:
//最小的单位,最大的单位(如定义mSmallestUnit(tuSeconds),mBiggestUnit(tuHours))
TimeUnit mSmallestUnit, mBiggestUnit;
QHash mFormatPattern;
// reimplemented virtual methods:
virtual double getTickStep(const QCPRange &range) ;
virtual int getSubTickCount(double tickStep) ;
virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) ;
//对特定的值value用指定文本text替换时间单位
void replaceUnit(QString &text, TimeUnit unit, int value) const;
};
void MainWindow::setupTestQCPAxisTickerTime()
{
customPlot->setInteraction(QCP::iRangeDrag, true);
customPlot->setInteraction(QCP::iRangeZoom, true);
customPlot->rescaleAxes();
QDateTime dateTime = QDateTime::currentDateTime();
QString dataString = dateTime.toString("yyyy:M:dd:hh:mm:ss");
qDebug()<<"*********"< timeTicker(new QCPAxisTickerTime);
customPlot->xAxis->setTicker(timeTicker);
timeTicker->setTickCount(6);
//设置刻度表示策略
timeTicker->setTickStepStrategy(QCPAxisTicker::tssMeetTickCount);
customPlot->xAxis->setSubTicks(false);
timeTicker->setTickOrigin(3600*3);//x轴起点坐标加3小时,即从当前hours+3开始
customPlot->xAxis->setRange(hours*3600, hours*3600 +3600*12);
customPlot->yAxis->setRange(-1000,1000);
timeTicker->setTimeFormat("%dday-%hhour");
QVector yData, xData;
for (int i = 0; i <= 24; i++){
xData.push_back(hours*3600 + i * 3600);
yData.push_back(pow(double(i), 2) + 550.0*sin(double(i)/4.0));
}
customPlot->addGraph();
customPlot->graph(0)->setData(xData, yData);
}
时间可以以毫秒、秒、分钟、小时和天显示。取决于通过setTimeFormat函数定义的最大可用单位,超过最大单位的。例如,如果格式字符串为"%M:%s",则为坐标值7815(2小时,10分钟和15秒)被创建,得到的刻度标签将显示"130:15"(130分钟,15秒)。如果格式字符串为"%H:%M:%s",则为"小时"。单位将被使用,标签将是“2:10:15”。
/*
设置文本刻度标签
*/
class QCPAxisTickerText : public QCPAxisTicker
{
public:
// getters:
QMap &ticks();//获得坐标轴标签
int subTickCount();//获得子刻度数目
// setters:
void setTicks(const QMap &ticks);//坐标轴标签添加坐标轴
void setTicks(const QVector &positions, const QVector labels);//坐标轴标签添加坐标轴
void setSubTickCount(int subTicks);//设置子刻度数目
// non-virtual methods:
void clear();
//addTick()坐标轴添加文本标签三种形式
void addTick(double position, QString label);
void addTicks(const QMap &ticks);
void addTicks(const QVector &positions, const QVector &labels);
protected:
// property members:
QMap mTicks;//坐标轴标签
int mSubTickCount;//子刻度数目
// reimplemented virtual methods:
virtual double getTickStep(const QCPRange &range) ;
virtual int getSubTickCount(double tickStep) ;
virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) ;
virtual QVector createTickVector(double tickStep, const QCPRange &range) ;
};
void MainWindow::setupTestQCPAxisTickerText()
{
//画柱状图
QCPBars *regen = new QCPBars(customPlot->xAxis, customPlot->yAxis);
regen->setAntialiased(false); // gives more crisp, pixel aligned bar borders
regen->setStackingGap(1);
regen->setName("Regenerative");
regen->setPen(QPen(QColor(0, 168, 140).lighter(130)));
regen->setBrush(QColor(0, 168, 140));
// stack bars on top of each other:
// regen->moveAbove(nuclear);
QVector ticks;
QVector labels;
ticks << 1 << 2 << 3 << 4 << 5 << 6 << 7;
labels << "USA" << "Japan" << "Germany" << "France" << "UK" << "Italy" << "Canada";
QSharedPointer textTicker(new QCPAxisTickerText);
textTicker->addTicks(ticks, labels);
customPlot->xAxis->setTicker(textTicker);
customPlot->xAxis->setTickLabelRotation(60);
customPlot->xAxis->setSubTicks(false);
customPlot->xAxis->setTickLength(0, 4);
customPlot->xAxis->setRange(0, 8);
customPlot->xAxis->setTickPen(QPen(Qt::white));
// prepare y axis:
customPlot->yAxis->setRange(0, 12.1);
customPlot->yAxis->setPadding(5); // a bit more space to the left border
customPlot->yAxis->setLabel("Power Consumption in\nKilowatts per Capita (2007)");
//customPlot->yAxis->setBasePen(QPen(Qt::white));
customPlot->yAxis->setTickPen(QPen(Qt::white));
customPlot->yAxis->setSubTickPen(QPen(Qt::white));
// Add data:
QVector regenData;
regenData << 0.06*10.5 << 0.05*5.5 << 0.04*5.5 << 0.06*5.8 << 0.02*5.2 << 0.07*4.2 << 0.25*11.2;
regen->setData(ticks, regenData);
}
class QCPAxisTickerPi : public QCPAxisTicker
{
public:
enum FractionStyle { fsFloatingPoint //分数被显示为规则十进制浮点数,例如“0.25”或“0.125”
,fsAsciiFractions //分数是用ASCII字符写成的有理数,例如“1/4”或“1/8”
,fsUnicodeFractions //分数使用子和上标UTF-8数字和分数符号来编写
};
QString piSymbol() const { return mPiSymbol; }//返回代替PI的符号标志
double piValue() const { return mPiValue; }//返回PI表示的值
bool periodicity() const { return mPeriodicity; }//是否周期性地出现
FractionStyle fractionStyle() const { return mFractionStyle; }//轴上数据分数显示风格
void setPiSymbol(QString symbol);//设置PI符号位的用symbol代替显示
void setPiValue(double pi);//设置PI表示的值,不指定PI表示默认值3.1415926....
//setPeriodicity()设置轴标签是否周期性地出现
//若要禁用周期性,将multiplesOfPi设置为0。例如将轴定义0到2PI的周期则会将multiplesOfPi设置为2
void setPeriodicity(int multiplesOfPi);
//设置轴的分数显示形式
void setFractionStyle(FractionStyle style);
protected:
QString mPiSymbol;
double mPiValue;
int mPeriodicity;
FractionStyle mFractionStyle;
double mPiTickStep; // size of one tick step in units of mPiValue
virtual double getTickStep(const QCPRange &range) ;
virtual int getSubTickCount(double tickStep) ;
virtual QString getTickLabel(double tick, const QLocale &locale, QChar formatChar, int precision) ;
void simplifyFraction(int &numerator, int &denominator) const;//对给定的分子numerator,分母denominator化成最简真分数
QString fractionToString(int numerator, int denominator) const;//转成字符串
QString unicodeFraction(int numerator, int denominator) const;//转成unicode编码
QString unicodeSuperscript(int number) const;//返回表示数字为上标的Unicode字符串
QString unicodeSubscript(int number) const;//返回表示数字为下标的Unicode字符串
};
void MainWindow::setupTestQCPAxisTickerPi()
{
QSharedPointer pITicker(new QCPAxisTickerPi());
customPlot->xAxis->setTicker(pITicker);
//pITicker->setPeriodicity(2);
//pITicker->setPiSymbol("--");
pITicker->setFractionStyle(QCPAxisTickerPi::fsUnicodeFractions);
pITicker->setPiValue(3.1415*2);//设置pi表示的值
customPlot->xAxis->setRange(0, 3.0*M_PI);
customPlot->xAxis->setVisible(true);
QVector x2(250), y2(250);
for (int i=0; i<250; ++i) // data for graphs 2, 3 and 4
{
x2[i] = i/250.0*3*M_PI;
y2[i] = qSin(x2[i]+ M_PI) + M_PI;
}
customPlot->addGraph(customPlot->xAxis, customPlot->yAxis);
customPlot->graph(0)->setData(x2, y2);
}
class QCPAxisTickerLog : public QCPAxisTicker
{
public:
QCPAxisTickerLog();
double logBase() const { return mLogBase; }
int subTickCount() const { return mSubTickCount; }
void setLogBase(double base);//设置对数的基数值
void setSubTickCount(int subTicks);//设置子刻度数目
protected:
double mLogBase;
int mSubTickCount;
double mLogBaseLnInv;
virtual double getTickStep(const QCPRange &range) ;
virtual int getSubTickCount(double tickStep) ;
virtual QVector createTickVector(double tickStep, const QCPRange &range) ;
};
void MainWindow::setupTestQCPAxisTickerLog()
{
QSharedPointer logTicker(new QCPAxisTickerLog);
customPlot->xAxis->setTicker(logTicker);
// don't forget to also set the scale type accordingly, otherwise you'll have
// logarithmically spaced ticks on a linear axis:
customPlot->xAxis->setScaleType(QCPAxis::stLogarithmic);
customPlot->xAxis->setRange(0,250);
logTicker->setLogBase(10);
QVector x2(250), y2(250);
for (int i=0; i<250; ++i) // data for graphs 2, 3 and 4
{
x2[i] = i;
y2[i] = log(i);
}
customPlot->addGraph(customPlot->xAxis, customPlot->yAxis);
customPlot->graph(0)->setData(x2, y2);
}
class QCPAxisTickerFixed : public QCPAxisTicker
{
public:
enum ScaleStrategy { ssNone //固定刻度,不允许修改
,ssMultiples //设置刻度间距为整数倍长度
,ssPowers //设置刻度间距为指数倍长度
};
// getters:
double tickStep() const { return mTickStep; }
ScaleStrategy scaleStrategy() const { return mScaleStrategy; }
// setters:
void setTickStep(double step);
void setScaleStrategy(ScaleStrategy strategy);
protected:
// property members:
double mTickStep;
ScaleStrategy mScaleStrategy;
// reimplemented virtual methods:
virtual double getTickStep(const QCPRange &range) ;
};