• Qt实战 数据统计柱状图显示


    前段时间有朋友找我做个问卷调查的软件,我说现在很多在线文档都有这功能,为啥还要使用Qt撸一个,他说要申请软著,我说,欧了。

    我们先看看WPS在线问卷的统计中,柱状图统计的效果吧

    我认为主要有以下几个关键点吧:

    1. 要做到根据窗口的宽度,大小自适应,避免硬编码
    2. 显示信息可配置
    3. 纵轴坐标文本需要计算宽度,过长时以省略号截尾
    4. 鼠标移动到柱状条上时,能够显示相应的文本,同时,背景高亮

    废话不多说,直接上代码了,ui文件就不放了,界面都是通过painter绘制的,没有任何控件。

    BarGraphStatistic.h

    1. #ifndef BARGRAPHSTATISTIC_H
    2. #define BARGRAPHSTATISTIC_H
    3. #include
    4. #include
    5. #include
    6. namespace Ui {
    7. class BarGraphStatistic;
    8. }
    9. class BarGraphStatistic : public QWidget
    10. {
    11. Q_OBJECT
    12. public:
    13. explicit BarGraphStatistic(const QVectorint>>& choices, QWidget *parent = nullptr);
    14. ~BarGraphStatistic();
    15. protected:
    16. void paintEvent(QPaintEvent* e);
    17. void mouseMoveEvent(QMouseEvent* e);
    18. void resizeEvent(QResizeEvent* e);
    19. private:
    20. void UpdateBarRect();
    21. private:
    22. Ui::BarGraphStatistic *ui;
    23. QVectorint>> m_choices;
    24. QString m_longestStr{""};
    25. int m_maxCnt{0};
    26. int m_fontSize{12};
    27. int m_padding{20};
    28. int m_itemHeight{45};
    29. int m_maxTxtWidth{200};
    30. int m_txtWidth;
    31. int m_txtHeight;
    32. int m_spaceHorizon{2};
    33. int m_axisXHeight{20};
    34. int m_winHeight;
    35. int m_barStartX;
    36. QVector m_barRects;
    37. int m_curBar = -1;
    38. QPoint m_mousePos;
    39. };
    40. #endif // BARGRAPHSTATISTIC_H

    BarGraphStatistic.cpp

    1. #include "BarGraphStatistic.h"
    2. #include "ui_BarGraphStatistic.h"
    3. #include
    4. #include
    5. #include
    6. #include
    7. BarGraphStatistic::BarGraphStatistic(const QVectorint>>& choices, QWidget *parent) :
    8. QWidget(parent),
    9. ui(new Ui::BarGraphStatistic),
    10. m_choices(choices)
    11. {
    12. ui->setupUi(this);
    13. setMouseTracking(true);
    14. for (int i = 0; i < m_choices.size(); ++i)
    15. {
    16. if (m_choices[i].first.size() > m_longestStr.size())
    17. m_longestStr = m_choices[i].first;
    18. if (m_choices[i].second > m_maxCnt)
    19. m_maxCnt = m_choices[i].second;
    20. }
    21. QFont f;
    22. f.setPixelSize(m_fontSize);
    23. QFontMetrics fm(f);
    24. auto tr = fm.boundingRect(m_longestStr);
    25. m_txtWidth = qMin(tr.width(), 100);
    26. m_txtHeight = tr.height();
    27. m_winHeight = m_padding * 2 + m_itemHeight * m_choices.size() + m_axisXHeight;
    28. m_barStartX = m_padding + m_txtWidth;
    29. setFixedHeight(m_winHeight);
    30. m_barRects.resize(m_choices.size());
    31. UpdateBarRect();
    32. }
    33. BarGraphStatistic::~BarGraphStatistic()
    34. {
    35. delete ui;
    36. }
    37. void BarGraphStatistic::paintEvent(QPaintEvent *e)
    38. {
    39. QPainter painter(this);
    40. {
    41. // draw background with white color
    42. painter.fillRect(this->rect(), QBrush(Qt::white));
    43. }
    44. {
    45. // draw axis
    46. painter.save();
    47. QPen pen;
    48. pen.setColor(Qt::gray);
    49. painter.setPen(pen);
    50. {
    51. int x0 = m_padding + m_txtWidth + m_spaceHorizon;
    52. int y0 = m_padding;
    53. int x1 = x0;
    54. int y1 = m_winHeight - m_padding - m_axisXHeight;
    55. painter.drawLine(x0, y0, x1, y1);
    56. }
    57. {
    58. int x0 = m_padding + m_txtWidth + m_spaceHorizon;
    59. int y0 = m_winHeight - m_padding - m_axisXHeight;
    60. int x1 = width() - m_padding;
    61. int y1 = y0;
    62. painter.drawLine(x0, y0, x1, y1);
    63. }
    64. {
    65. int x = m_padding + m_txtWidth + m_spaceHorizon;
    66. int y = m_padding + m_itemHeight * m_choices.size();
    67. int w = width() - x - m_padding;
    68. int h = m_axisXHeight;
    69. painter.drawText(x, y, w, h, Qt::AlignLeft, "0");
    70. painter.drawText(x, y, w, h, Qt::AlignRight, QString::number(m_maxCnt + 1));
    71. }
    72. painter.restore();
    73. }
    74. {
    75. painter.save();
    76. QFont f;
    77. f.setPixelSize(m_fontSize);
    78. painter.setFont(f);
    79. for (int i = 0; i < m_choices.size(); ++i)
    80. {
    81. {
    82. int x = m_padding;
    83. int y = m_padding + i * m_itemHeight;
    84. int w = m_txtWidth;
    85. int h = m_itemHeight;
    86. QFontMetrics fm(f);
    87. auto txt = fm.elidedText(m_choices[i].first, Qt::ElideRight, w);
    88. painter.drawText(QRect(x, y, w, h), Qt::AlignVCenter|Qt::AlignRight, txt);
    89. }
    90. {
    91. if (m_curBar == i)
    92. {
    93. painter.fillRect(m_barRects[i], QColor(10, 108, 255, 20));
    94. }
    95. int x = m_padding + m_txtWidth + m_spaceHorizon;
    96. int y = m_padding + i * m_itemHeight + m_itemHeight/4;
    97. int w = (width() - m_padding - m_txtWidth - m_spaceHorizon - m_padding) * m_choices[i].second / (m_maxCnt + 1);
    98. int h = m_itemHeight/2;
    99. painter.fillRect(x, y, w, h, QColor(10, 108, 255));
    100. x = x + w + m_spaceHorizon;
    101. y = m_padding + i * m_itemHeight;
    102. w = (width() - m_padding - m_txtWidth - m_spaceHorizon - m_padding) - w;
    103. h = m_itemHeight;
    104. painter.drawText(x, y, w, h, Qt::AlignVCenter|Qt::AlignLeft, QString::number(m_choices[i].second));
    105. }
    106. }
    107. if (m_curBar >=0 && m_curBar < m_choices.size())
    108. {
    109. painter.save();
    110. auto text = QString("%1: %2").arg(m_choices[m_curBar].first).arg(m_choices[m_curBar].second);
    111. auto font = painter.font();
    112. font.setPixelSize(12);
    113. QFontMetrics fm(font);
    114. auto br = fm.boundingRect(text);
    115. const int maxWidth = 500;
    116. auto w = qMin(maxWidth, br.width()+10);
    117. auto h = br.width() * br.height()/w +20;
    118. QRect rect;
    119. if (m_mousePos.x() + w + 10 > width())
    120. rect = QRect(m_mousePos + QPoint(-10-w, 10), QSize(w, h));
    121. else
    122. rect = QRect(m_mousePos + QPoint(10, 10), QSize(w, h));
    123. painter.setFont(font);
    124. QTextOption tOpt(Qt::AlignTop|Qt::AlignLeft);
    125. tOpt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    126. painter.drawText(rect, text, tOpt);
    127. painter.restore();
    128. }
    129. painter.restore();
    130. }
    131. }
    132. void BarGraphStatistic::mouseMoveEvent(QMouseEvent *e)
    133. {
    134. int cur = -1;
    135. for (int i = 0; i < m_barRects.size(); ++i)
    136. {
    137. if (m_barRects[i].contains(e->pos()))
    138. {
    139. cur = i;
    140. break;
    141. }
    142. }
    143. // if (cur != m_curBar)
    144. {
    145. m_curBar = cur;
    146. m_mousePos = e->pos();
    147. update();
    148. }
    149. }
    150. void BarGraphStatistic::resizeEvent(QResizeEvent *e)
    151. {
    152. UpdateBarRect();
    153. }
    154. void BarGraphStatistic::UpdateBarRect()
    155. {
    156. for (int i = 0; i < m_choices.size(); ++i)
    157. {
    158. int x = m_padding + m_txtWidth + m_spaceHorizon;
    159. int y = m_padding + i * m_itemHeight;
    160. int w = width() - m_padding - m_txtWidth - m_spaceHorizon - m_padding;
    161. int h = m_itemHeight;
    162. m_barRects[i] = QRect{x, y, w, h};
    163. }
    164. }

    下面是我实现的最终效果,是不是还挺像的,如果感觉那里不好,大家就自己去修改源码吧。

  • 相关阅读:
    Java 接口的学习笔记
    黑豹程序员-架构师学习路线图-百科:Mybatis的伴侣MybatisPlus
    MATLB|电动汽车充放电的最优调度
    力扣二分查找:第一个错误的版本
    广东海洋大学计算机考研资料汇总
    数据结构(12)Dijkstra算法JAVA版:图的最短路径问题
    MobLink iOS端快速集成文档
    java反射
    Android控件全解手册 - 1.5万字了解Button的一切
    十三届蓝桥杯c/c++省赛C组
  • 原文地址:https://blog.csdn.net/u013001137/article/details/131591109