这一篇我们详细介绍图表各个部分的设置和操作,包括图表的标题、图例、边距等属性设置,QLineSeries序列的属性设置,QValueAxis坐标轴的属性设置,以及图标的缩放。(这些应该都是在实际的Qt开发中比较常用的图表操作)先看运行时的界面:
界面设计
工具栏:创建几个
Action
,并创建工具栏,实现图表数据刷新和缩放功能。主工作区图标视图:从组件面板放置一个
QGraphics View
组件作为视图组件,并用Promote
方法升级为QChartView
组件,命名为chartView
。图表属性设置面板:左侧是一个
QToolBox
组件,分为3个操作面板,用于进行图表设置、曲线设置和坐标轴设置。
主窗口类的定义和初始化
下面是主窗口类MainWindow
的类定义(省略了Action和界面组件的槽函数定义)。在mainwindow.h
文件重需要包含QtChart
,并使用宏QT_CHARTS_USE_NAMESPACE
导入命名空间。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtCharts>
QT_CHARTS_USE_NAMESPACE
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QLineSeries* curSeries; // 当前序列
QValueAxis* curAxis; // 当前坐标轴
void createChart(); // 创建图表
void prepareData(); // 更新数据
void updateFromChart(); // 从图表更新到界面
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
在MainWindow
类中定义了两个私有的变量,curSeries
用于指向当前的QLineSeries
序列,界面上对序列的设置操作都是针对当前选择的序列;curAxis
用于指向当前的QValueAxis
坐标轴,对坐标轴进行设置时就是针对当前坐标轴进行设置。
createChart()
函数用于创建图表的各个基本部件,在构造函数里调用,prepareData()
用于更新序列的数据,updateFormChart()
用于读取图表的一些属性,并刷新界面显示。下面是主窗口构造函数,以及这3个函数的代码。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
createChart(); // 创建图表
prepareData(); // 生成数据
updateFromChart(); // 从图表获取属性值,刷新到界面显示
}
void MainWindow::createChart()
{
QChart* chart = new QChart();
chart->setTitle("简单函数曲线");
ui->chartView->setChart(chart);
ui->chartView->setRenderHint(QPainter::Antialiasing); // 抗锯齿,平滑
QLineSeries* series0 = new QLineSeries();
QLineSeries* series1 = new QLineSeries();
series0->setName("Sin 曲线");
series1->setName("Cos 曲线");
curSeries = series0;
QPen pen;
pen.setStyle(Qt::DotLine);
pen.setWidth(2);
pen.setColor(Qt::red);
series0->setPen(pen);
pen.setStyle(Qt::SolidLine);
pen.setColor(Qt::blue);
series1->setPen(pen);
chart->addSeries(series0);
chart->addSeries(series1);
QValueAxis* axisX = new QValueAxis();
curAxis = axisX;
axisX->setRange(0, 10);
axisX->setLabelFormat("%.1f"); // 标签格式
axisX->setTickCount(11); // 主分隔个数
axisX->setMinorTickCount(9); // 次分隔个数
axisX->setTitleText("time(secs)"); // 标题
QValueAxis* axisY = new QValueAxis();
axisY->setRange(-2, 2);
axisY->setTitleText("value");
axisY->setTickCount(5);
axisY->setLabelFormat("%.2f");
axisY->setMinorTickCount(4);
chart->setAxisX(axisX, series0);
chart->setAxisY(axisY, series0);
chart->setAxisX(axisX, series1);
chart->setAxisY(axisY, series1);
}
void MainWindow::prepareData()
{
QLineSeries* series0 = (QLineSeries*)ui->chartView->chart()->series().at(0);
QLineSeries* series1 = (QLineSeries*)ui->chartView->chart()->series().at(1);
series0->clear();
series1->clear();
qsrand(QTime::currentTime().second()); // 初始化随机数
qreal t = 0;
qreal y1, y2;
qreal intv = 0.1;
qreal rd;
int cnt = 100;
for (int i = 0; i < cnt; i++) {
rd = (qrand() % 10) - 5;
y1 = qSin(t) + rd / 50;
series0->append(t, y1);
rd = (qrand() % 10) - 5;
y2 = qCos(t) + rd / 50;
series1->append(t, y2);
t += intv;
}
}
void MainWindow::updateFromChart()
{
QChart* chart = ui->chartView->chart();
ui->editTitle->setText(chart->title());
QMargins mg = chart->margins(); // 边距
ui->spinMarginTop->setValue(mg.top());
ui->spinMarginLeft->setValue(mg.left());
ui->spinMarginRight->setValue(mg.right());
ui->spinMarginBottom->setValue(mg.bottom());
}
MainWindow
类个构造函数调用单个私有函数进行图表和界面的初始化。createChart()
函数用于创建QChart对象,创建数据序列和坐标轴,并将这些部件组合成一个完整的图表。prepareDate()
函数用于为图表重的两个序列生成数据,其中使用随机数,以便使得每次生成的数据稍有不同。updateFromChart()
函数用于将图表重的标题和边距信息显示到窗口界面上。
笔画设置对话框QWDialogPen
在这个demo中,需要设置一些对象的pen属性,比如折线序列的pen属性,网络先的pen属性等。pen属性其实就是一个QPen对象,设置内容主要包括线型,线宽和颜色。为了使用方便,设计一个自定义对话框QWDialogPen,专门用于QPen对象的属性设置。
QWDialogPen是一个可视化设计的对话框,其类型定义如下:
class QWDialogPen : public QDialog
{
Q_OBJECT
public:
explicit QWDialogPen(QWidget *parent = nullptr);
~QWDialogPen();
void setPen(QPen pen); // 设置Qpen,用于对话框界面显示
QPen getPen(); // 获取对话框设置的QPen属性
static QPen getPen(QPen iniPen, bool& ok); //静态函数
private slots:
void on_btnColor_clicked();
private:
Ui::QWDialogPen *ui;
QPen m_pen;
};
QWDialogPen类的getPen()
以及相关函数的实现代码如下:
void QWDialogPen::setPen(QPen pen)
{
m_pen = pen;
ui->spinWidth->setValue(pen.width());
int i = static_cast<int>(pen.style());
ui->comboPenStyle->setCurrentIndex(i);
QColor color = pen.color();
ui->btnColor->setAutoFillBackground(true);
QString str = QString::asprintf("background-color: rgb(%d,%d,%d);", color.red(), color.green(), color.blue());
ui->btnColor->setStyleSheet(str);
}
QPen QWDialogPen::getPen()
{
m_pen.setStyle(Qt::PenStyle(ui->comboPenStyle->currentIndex()));
m_pen.setWidth(ui->spinWidth->value());
QColor color = ui->btnColor->palette().color(QPalette::Button);
m_pen.setColor(color);
return m_pen;
}
QPen QWDialogPen::getPen(QPen iniPen, bool &ok)
{
QWDialogPen* dlg = new QWDialogPen();
dlg->setPen(iniPen);
QPen pen;
int ret = dlg->exec(); // 弹出对话框
if (ret == QDialog::Accepted) {
pen = dlg->getPen(); // 获取
ok = true;
}
else {
pen = iniPen;
ok = false;
}
delete dlg; // 删除对话框对象
return pen; //返回设置的QPen对象
}
静态函数getPen()
里创建了一个QWDialogPen
类的实例dlg
,然后调用dlg→setPen(iniPen)
进行初始化,运行对话框并获取返回值,若返回值为QDialog::Accepted
,就调用dlg→getPen()
获取设置属性后的QPen对象,最后删除对话框对象并返回设置的Qpen对象。所以,静态函数getPen()
就是集成了普通方法调用对话框时创建对话框,设置初始值、获取对话框返回状态、获取返回删除对话框的过程,简化了调用代码。
QChart设置
QChart类的主要函数
分组 | 函数名 | 功能描述 |
---|---|---|
图表外观 | void setTitle() | 设置图表标题,支持HTML |
void setTitleFont() | 设置图表标题字体 | |
void setTitleBrush() | 设置比图表标题画刷 | |
void setTheme() | 设置主题,定义了图表的配色 | |
void setMargins() | 设置绘图区与图表边界的四个边距 | |
QLegend* legend() | 返回图表的图例,是一个QLegend类对象 | |
void setAnimationOptions() | 设置序列或坐标轴的动画效果 | |
数据序列 | void addSeries() | 添加序列 |
QList<QAbstractSeries*>series() | 返回图表拥有的序列的列表 | |
void removeSeries() | 移除一个序列,但并不删除序列对象 | |
void removeAllSeries() | 移除并删除图表的所有序列 | |
坐标轴 | void addAxis() | 为图表的某个方向添加坐标轴 |
QList<QAbstractSeries*> axes() | 返回某个方向的坐标轴列表 | |
void setAxisX() | 设置某个序列的水平方向的坐标轴 | |
void setAxisY() | 设置某个序列的垂直方向的坐标轴 | |
void removeAxis() | 移除一个坐标轴 | |
void createDefaultAxes() | 更具已添加的序列类型,创建缺省的坐标轴,前面已有的坐标轴会被删除 |
通过图表的设置界面可以设置标题的内容和字体,可以设置图例的位置,是否显示,字体颜色和边距;可以设置动画效果和主题。
setAnimationOptions(AnimationOptions options)
函数设置图表的动画效果,输入参数是QChart::AnimationOption
枚举类型,有以下取值:
QChart::NoAnimation:无动画效果;
QChart::GridAxisAnimations:背景网格有动画;
QChart::SeriesAnimations:序列有动画效果;
QChart::AllAnimations:都有动画效果。
主题是预定义的图表配色样式,是QChart::ChartTheme
枚举类型,有多种取值。
图例是一个QLegend
类对象,通过QChart::legend()
可以获取图表的图例。图例是根据添加的序列自动生成的,但是可以修改一些属性,如:位置,文字和字体等。例如:
ui->chartView->chart()->legend()->setAlignment(Qt::AlignBottom);
void MainWindows::on_btnLegendFont_clicked() {
QFont font = ui->chartView->chart()->legend()->font();
bool ok = false;
font = QFontDialog::getFont(&ok, font);
if (ok) {
ui->chartView->chart()->legend()->setFont(font);
}
}