柱状图柱状图Qt 柱状图的核心组件在 Qt Charts 中绘制柱状图主要涉及以下核心组件●QBarSet用于存储柱状图中的一组数据。●QBarSeries包含多个 QBarSet代表一组柱状图。●QChart图表的核心对象管理所有的系列、图例和标题。●QChartView用于在界面上显示 QChart 的视图组件类似于 QGraphicsView。●QValueAxis 和 QCategoryAxis用于设置图表的值轴和类别轴。示例场景完成基本的柱状图Jane, John,Axel对应的就是三个QBarSet我们分别向三个QBarSet写入六组数据对应的就是下面六个月分产生的纵轴的值。解决思路1 先在构造函数中添加柱状图要用到的成员class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent nullptr); ~MainWindow(); private: Ui::MainWindow *ui; // Qt Charts 成员 QChartView *chartView; QChart *chart; QBarSeries *series; //三个集合每个坐标对应三个柱子 QBarSet *set0; QBarSet *set1; QBarSet *set2; };实现构造函数MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), chartView(new QChartView(this)) , chart(new QChart()) , series(new QBarSeries()) , set0(new QBarSet(Jane)) , set1(new QBarSet(John)) , set2(new QBarSet(Axel)) { ui-setupUi(this); // 初始化数据 *set0 1 2 3 4 5 6; *set1 5 0 0 4 0 7; *set2 3 5 8 13 8 5; // 添加 QBarSet 到 QBarSeries series-append(set0); series-append(set1); series-append(set2); // 添加系列到图表 chart-addSeries(series); chart-setTitle(简单的柱状图示例); chart-setAnimationOptions(QChart::SeriesAnimations); // 设置类别轴 QStringList categories; categories Jan Feb Mar Apr May Jun; QBarCategoryAxis *axisX new QBarCategoryAxis(); axisX-append(categories); chart-addAxis(axisX, Qt::AlignBottom); series-attachAxis(axisX); // 设置值轴 QValueAxis *axisY new QValueAxis(); axisY-setRange(0, 15); chart-addAxis(axisY, Qt::AlignLeft); series-attachAxis(axisY); // 设置图表到视图 chartView-setChart(chart); chartView-setRenderHint(QPainter::Antialiasing); // 设置布局 QVBoxLayout *layout new QVBoxLayout(); layout-addWidget(chartView); QWidget *widget new QWidget(); widget-setLayout(layout); setCentralWidget(widget); resize(800,600); }柱状图美化(扩展内容)为了使柱状图更具美观性和可读性可以进行多种定制和美化操作包括设置柱状条颜色添加标签和数值设置轴和标题设定图表主题添加动画效果设置柱状条颜色可以为不同的柱状条设置不同的颜色以增强视觉效果。// 设置每个 QBarSet 的颜色 set0-setColor(Qt::red); set1-setColor(Qt::green); set2-setColor(Qt::blue);将以上代码添加到mainwindow.cpp中// 添加 QBarSet 到 QBarSeries之后。添加标签和数值为柱状条添加标签以显示数值信息。// 显示每个柱状条的数值标签 set0-setLabelRotation(0); set1-setLabelRotation(0); set2-setLabelRotation(0); set0-setLabelVisible(true); set1-setLabelVisible(true); set2-setLabelVisible(true);将以上代码添加到柱状条颜色设置之后。设置轴和标题自定义轴的范围、标题等属性。// 设置 X 轴标题 axisX-setTitleText(月份); // 设置 Y 轴标题 axisY-setTitleText(销售量);将以上代码添加到轴设置之后。设定图表主题Qt Charts 提供了多种内置主题可以快速改变图表的整体风格。chart-setTheme(QChart::ChartThemeQt);可选主题列表包括ChartThemeLightChartThemeBlueCeruleanChartThemeDarkChartThemeBrownSandChartThemeBlueNcsChartThemeHighContrastChartThemeBlueIcyChartThemeQt默认将以上代码添加到图表初始化部分。添加动画效果通过设置动画选项使图表在数据变化时具有过渡效果。chart-setAnimationOptions(QChart::AllAnimations);动态更新柱状图在MainWindow的构造函数中我们将原来加载数据的方式改为先初始化三个QVector容器里面存储我们将要用到的数据//分别初始化三组数据将来用作三个BarSet data0 {1, 2, 3, 4, 5, 6}; data1 {5, 0, 0, 4, 0, 7}; data2 {3, 5, 8, 13, 8, 5};因为三个QVector大小一致我们可以通过一次遍历分别取出vector中的元素添加到不同的QBarSet中//初始化三个BarSet for(int i 0; i data0.size(); i){ //依次向三个集合添加数据 set0-append(data0[i]); set1-append(data1[i]); set2-append(data2[i]); }之后的逻辑和之前是一致的, 我们这里创建定时器//初始化定时器 timer new QTimer(this); //连接定时器超时逻辑 connect(timer, QTimer::timeout,this, MainWindow::updateChart); //每隔2s更新依次 timer-start(2000);定时器的回调函数void MainWindow::updateChart(){ int maxVal -1; // 模拟数据变化随机增加或减少每个 QBarSet 的值 for (int i 0; i set0-count(); i) { int change0 QRandomGenerator::global()-bounded(-2, 3); // -2到2 int change1 QRandomGenerator::global()-bounded(-2, 3); int change2 QRandomGenerator::global()-bounded(-2, 3); data0[i] change0; data1[i] change1; data2[i] change2; // 确保数据不为负数 if (data0[i] 0) data0[i] 0; if (data1[i] 0) data1[i] 0; if (data2[i] 0) data2[i] 0; // 更新 QBarSet 的值 set0-replace(i,data0[i]); set1-replace(i,data1[i]); set2-replace(i,data2[i]); //定义QList用来获取最大值 QListint temp_list; temp_list data0[i] data1[i] data2[i] maxVal; //获取最大元素的迭代器 auto max_iter std::max_element(temp_list.begin(),temp_list.end()); if(max_iter ! temp_list.end()){ maxVal *max_iter; } } qDebug() maxval is maxVal; // 动态调整 Y 轴范围 // 基类向子类转换用qobject_cast QValueAxis *axisY qobject_castQValueAxis*(chart-axisY()); if (axisY) { axisY-setRange(0, maxVal 5); } }再次启动程序运行后会发现每隔两秒数据就更新一次。捕获事件信号想实现如下图的悬浮效果QBarSet同样具有点击信号和悬浮信号被点击时发出如下信号[signal] void QBarSet::clicked(int index)悬浮时发出信号[signal] void QBarSet::hovered(bool status, int index)在构造函数中连接点击信号//连接点击信号 for(auto bar_set : series-barSets()){ //连接点击事件 connect(bar_set, QBarSet::clicked, this,MainWindow::handleBarClicked); }实现点击函数因为信号里只有一个index我们需要通过sender()方法获取发送信号的对象sender()返回的是QObject,进而转为具体的对象类型//处理点击事件 void MainWindow::handleBarClicked(int index) { //此处获得信号的发送者 QBarSet *barSet qobject_castQBarSet*(sender()); if (barSet) { QMessageBox::information(this, 柱状条点击, QString(您点击了 %1, 数据为 %2).arg(barSet-label()) .arg(barSet-at(index))); } }同样在构造函数中连接悬浮信号//连接信号 for(auto bar_set : series-barSets()){ //连接点击事件 connect(bar_set, QBarSet::clicked, this,MainWindow::handleBarClicked); //连接悬浮信号 connect(bar_set,QBarSet::hovered, this,MainWindow::handleBarHovered); }实现悬浮事件回调函数//处理鼠标悬浮事件 void MainWindow::handleBarHovered(bool status, int index) { //此处获得信号的发送者 QBarSet *barSet qobject_castQBarSet*(sender()); if(!barSet){ return; } //处理未悬浮在数据的情况 if (!status) { QToolTip::hideText(); } auto label_str barSet-label(); auto num barSet-at(index); QToolTip::showText(QCursor::pos(), QString(%1:数据为%2).arg(label_str).arg(num)); }