数据柱形图显示
1、我们首先把这个这个视图的表格部分表示出来
mainwindow.h
/** * 书本:【Qt5开发及实例】 * 功能:数据柱形图显示,这个类是表格显示 * 文件:mainwindow.h * 时间:2015年1月28日18:50:54 * 作者:cutter_point */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QStandardItemModel> #include <QSplitter> #include <QMenu> #include <QMenuBar> #include <QTableView> #include <QString> #include "histogramview.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); //创建文件里面的打开动作 void createAction(); //创建菜单栏 void createMenu(); //设置模型 void setupModel(); //设置显示视图 void setupView(); //读取打开的文件 void openFile(QString); public slots: //打开文件读取文件的槽函数 void slotOpen(); private: //私有的控件成员 QMenu *fileMenu; //文件菜单 QAction *openAct; //打开文件事件 QStandardItemModel *model; //界面模型 QTableView *table; //表格视图 QSplitter *splitter; //界面的分割布局 HistogramView *histogram; }; #endif // MAINWINDOW_H
mainwindow.cpp
/** * 书本:【Qt5开发及实例】 * 功能:数据柱形图显示 * 文件:mainwindow.h * 时间:2015年1月28日18:50:54 * 作者:cutter_point */ #include "mainwindow.h" #include <QFileDialog> #include <QDebug> MainWindow::MainWindow(QWidget *parent) //构造函数 : QMainWindow(parent) { createAction(); //生成相应的事件 createMenu(); //生成菜单 setupModel(); //设置模型 setupView(); //显示视图 //设置标题和界面大小 this->setWindowTitle(tr("cutter_point")); this->resize(600, 600); } MainWindow::~MainWindow() { } //创建文件里面的打开动作 //void createAction(); void MainWindow::createAction() { //创建我们的打开事件 openAct = new QAction(tr("open"), this); //连接上打开文件 connect(openAct, SIGNAL(triggered()), this, SLOT(slotOpen())); //点击选择这个事件连接上这个槽函数 } //创建菜单栏 //void createMenu(); void MainWindow::createMenu() { //设置文件菜单 fileMenu = new QMenu(tr("file"), this); fileMenu->addAction(openAct); //为这个菜单栏加入一个选项 this->menuBar()->addMenu(fileMenu); //加入到主窗口的菜单行中 } //设置模型 //void setupModel(); void MainWindow::setupModel() { model = new QStandardItemModel(4, 4, this); //在当前的窗口中创建一个4行4列的标准模型 //头标题就是4个,部门,男,女,退休 model->setHeaderData(0, Qt::Horizontal, tr("department")); //部门 model->setHeaderData(1, Qt::Horizontal, tr("male")); //男 model->setHeaderData(2, Qt::Horizontal, tr("female")); //女 model->setHeaderData(3, Qt::Horizontal, tr("retirement")); //退休 } //设置显示视图 //void setupView(); void MainWindow::setupView() { //设置好表格视图 table = new QTableView; table->setModel(model); //设置这个表格视图的模型 QItemSelectionModel *selectionModel = new QItemSelectionModel(model); table->setSelectionModel(selectionModel); splitter = new QSplitter; //分割界面 splitter->setOrientation(Qt::Vertical); //垂直分割 // histogram = new HistogramView; histogram = new HistogramView(splitter); histogram->setModel(model); //添加到这个模型中 histogram->setSelectionModel(selectionModel); splitter->addWidget(table); splitter->addWidget(histogram); this->setCentralWidget(splitter); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), table, SLOT(selectionChanged(QItemSelection,QItemSelection))); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), histogram, SLOT(selectionChanged(QItemSelection,QItemSelection))); } //打开文件读取文件的槽函数 //void slotOpen(); void MainWindow::slotOpen() { QString name; //文件名 name = QFileDialog::getOpenFileName(this, "open", ".", "file(*.txt; *.doc)"); //设置文件打开对话框 if(!name.isEmpty()) //取得文件 { //打开文件,读取文件里面的数据 this->openFile(name); } } //读取打开的文件 // void openFile(); void MainWindow::openFile(QString path) { //如果得到的路径不为空 if(!path.isEmpty()) { QFile file(path); //取得文件 qDebug()<<path; //看看路径的格式 if(file.open(QFile::ReadOnly | QFile::Text)) //打开文件里面只有文本,并且是只读格式,表示打开成功 { QTextStream stream(&file); //文件读取流 QString line; //保存一行数据 model->removeRows(0, model->rowCount(QModelIndex()), QModelIndex()); //删除从第一个index到第二个index的行,总之先清除各行 int row = 0; //第0行 do { line = stream.readLine(); //读取一行 //如果读取到了数据 if(!line.isEmpty()) { model->insertRow(row, QModelIndex()); //把第row行数据插入,那个QModelIndex()是个什么东西??? QStringList pieces = line.split(",", QString::SkipEmptyParts); //把这行数据按“,”分开,然后空白的部分不要 model->setData(model->index(row, 0, QModelIndex()), pieces.value(0)); //插入一行的第一个数据 model->setData(model->index(row, 1, QModelIndex()), pieces.value(1)); //插入一行的第一个数据 model->setData(model->index(row, 2, QModelIndex()), pieces.value(2)); //插入一行的第一个数据 model->setData(model->index(row, 3, QModelIndex()), pieces.value(3)); //插入一行的第一个数据 //下一行 row++; }//if(!line.isEmpty()) }while(!line.isEmpty()); //当读取到空的数据的时候就退出 file.close(); //关闭文件流 }//if(file.open(QFile::ReadOnly | QFile::Text)) }// if(!path.isEmpty()) }//void MainWindow::openFile(QString path)
2、然后我们开始绘画条状图
histogramview.h
/** * 书本:【Qt5开发及实例】 * 功能:数据柱形图显示,这个类是柱形图 * 文件:histogramview.h * 时间:2015年1月28日20:23:40 * 作者:cutter_point */ #ifndef HISTOGRAMVIEW_H #define HISTOGRAMVIEW_H #include <QAbstractItemView> #include <QItemSelectionModel> #include <QRegion> #include <QMouseEvent> class HistogramView : public QAbstractItemView { Q_OBJECT public: explicit HistogramView(QWidget *parent = 0); //这里有些继承来的纯虚函数,可以实现,但必须声明 // virtual QRect visualRect(const QModelIndex &index) const = 0; // virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) = 0; // virtual QModelIndex indexAt(const QPoint &point) const = 0; QRect visualRect(const QModelIndex &index) const; void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible); QModelIndex indexAt(const QPoint &point) const; //绘制柱形图的函数 void paintEvent(QPaintEvent *); //为selections赋初值 // QAbstractItemView interface void setSelectionModel(QItemSelectionModel *selectionModel); //当鼠标在按下的时候调用setSelection函数,确定鼠标点击点所在的区域,设置选择项 void mousePressEvent(QMouseEvent *event); //选中区域是属于什么 QRegion itemRegion(QModelIndex index); signals: public slots: protected slots: void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); protected: QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers); int horizontalOffset() const; int verticalOffset() const; bool isIndexHidden(const QModelIndex &index) const; void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command); QRegion visualRegionForSelection(const QItemSelection &selection) const; // virtual QModelIndex moveCursor(CursorAction cursorAction, // Qt::KeyboardModifiers modifiers) = 0; // virtual int horizontalOffset() const = 0; // virtual int verticalOffset() const = 0; // virtual bool isIndexHidden(const QModelIndex &index) const = 0; // virtual void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) = 0; // virtual QRegion visualRegionForSelection(const QItemSelection &selection) const = 0; private: QItemSelectionModel *selections; QList<QRegion> MRegionList; QList<QRegion> FRegionList; QList<QRegion> SRegionList; }; #endif // HISTOGRAMVIEW_H
histogramview.cpp
/** * 书本:【Qt5开发及实例】 * 功能:数据柱形图显示,这个类是柱形图 * 文件:histogramview.cpp * 时间:2015年1月28日20:36:24 * 作者:cutter_point */ #include "histogramview.h" #include <QPainter> //绘画工具 #include <QDebug> HistogramView::HistogramView(QWidget *parent) : QAbstractItemView(parent) { } //绘制柱形图的函数 //void paintEvent(QPaintEvent *); void HistogramView::paintEvent(QPaintEvent *) { QPainter painter(viewport()); //这个就是在这个viewport范围内建立一个绘画对象,这个viewport就是给定的范围,大小暂时不知,反正就是一个地方 painter.setPen(Qt::yellow); //来一只黄色的笔 int x0 = 40; int y0 = 250; //来了,坐标0号 //y坐标轴 painter.drawLine(x0,y0,40,30); //高 painter.drawLine(38,32,40,30); //这是两个箭头 painter.drawLine(40,30,42,32); painter.drawText(20,30,tr("人数")); //坐标轴后面的给个文字 for(int i=1; i<5; i++) //y坐标的刻度 { painter.setPen(Qt::black); //来一只黑色的笔 painter.drawLine(x0, i*50, 50, i*50); // qDebug()<<"=======Chinese????"<<i; painter.drawText(20, (5-i)*50, tr("%1").arg(i*5)); } //x 坐标轴 painter.setPen(Qt::yellow); //来一只黄色的笔 painter.drawLine(x0,y0,540,250); painter.drawLine(538,248,540,250); painter.drawLine(540,250,538,252); painter.drawText(545,250,tr("部门")); //接下来一个一个地画图形 //部门 int posD = x0 + 20; //重这里开始画,后面可以看到相当于重表示男人数的柱子下面开始写 int row; //标记写到了第几行 for(row = 0; row < model()->rowCount(this->rootIndex()); ++row) //model() 返回已经呈现的视图 {//rootIndex统计最开始的那个索引 // qDebug()<<this->rootIndex(); //这个根索引 QModelIndex index = model()->index(row, 0, rootIndex()); //得到第row行,第1列,第0个的索引 QString dep = model()->data(index).toString(); //得到这个索引的数据 painter.drawText(posD, y0 + 20, dep); //dep就是刚得到的部门信息 posD += 50; //下一个 } //男 // qDebug()<<"111111"; int posM=x0+20; for(row=0; row<model()->rowCount(rootIndex()); ++row) { QModelIndex index=model()->index(row,1,rootIndex()); //第二列 int male=model()->data(index).toDouble(); //数值转化 // qDebug()<<index; int width=10; //柱形图柱子的宽度 // qDebug()<<"1111111"; //注意这里selection还没有初值,也就是还没有实例对象,没有模型对象 if(selections->isSelected(index)) //用不同的颜色区别选择的部分和未选择的部分,index是这一行的索引 { qDebug()<<"1111111ifififififif"; painter.setBrush(QBrush(Qt::black,Qt::Dense3Pattern)); //设置画刷 } else { // qDebug()<<"1111111elseelseelseelse"; painter.setBrush(Qt::blue); } // qDebug()<<"22222"; painter.drawRect(QRect(posM,y0-male*10,width,male*10)); //画柱子,宽度已设置为10 QRegion regionM(posM,y0-male*10,width,male*10); //剪裁一个区域的大小记录下来 MRegionList<<regionM; //把占据的区域保存下来给后面使用 posM+=50; } // qDebug()<<"22222"; //女 // qDebug()<<"女1"; int posF=x0+30; //这里是吧位置设置到离上面为10 的地方 for(row=0; row<model()->rowCount(rootIndex()); ++row) { QModelIndex index=model()->index(row,2,rootIndex());//第三列 int female=model()->data(index).toDouble(); int width=10; if(selections->isSelected(index)) //用不同的颜色区别选择的部分和未选择的部分,index是这一行的索引 painter.setBrush(QBrush(Qt::black,Qt::Dense3Pattern)); else painter.setBrush(Qt::red); //没选中就是红色 painter.drawRect(QRect(posF,y0-female*10,width,female*10)); QRegion regionF(posF,y0-female*10,width,female*10); //剪裁一个区域的大小记录下来 FRegionList<<regionF; //把占据的区域保存下来给后面使用 posF+=50; } // qDebug()<<"女2"; //退休 // qDebug()<<"退休1"; int posS=x0+40; for(row=0;row<model()->rowCount(rootIndex());row++) { QModelIndex index=model()->index(row,3,rootIndex()); int retire=model()->data(index).toDouble(); int width=10; if(selections->isSelected(index)) //用不同的颜色区别选择的部分和未选择的部分,index是这一行的索引 painter.setBrush(QBrush(Qt::black,Qt::Dense3Pattern)); else painter.setBrush(Qt::green); painter.drawRect(QRect(posS,y0-retire*10,width,retire*10)); QRegion regionS(posS, y0-retire*10, width, retire*10); //就是把在(posS, y0-retire)开始高度retire*10和宽度10的区域 SRegionList<<regionS; posS+=50; }//for(row=0;row<model()->rowCount(rootIndex());row++) // qDebug()<<"退休2"; }//void HistogramView::paintEvent(QPaintEvent *) //当模型的数据改变的时候,调用绘图设备的update函数更新 void HistogramView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { QAbstractItemView::dataChanged(topLeft, bottomRight); this->viewport()->update(); //在这个基础上改变更新 } //设置selections的初值 void HistogramView::setSelectionModel(QItemSelectionModel *selectionModel) { selections = selectionModel; } QRect HistogramView::visualRect(const QModelIndex &index)const { QRect *p = new QRect(); return *p; } void HistogramView::scrollTo(const QModelIndex &index,ScrollHint){} QModelIndex HistogramView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) { return QModelIndex(); } int HistogramView::horizontalOffset()const { return 0; } int HistogramView::verticalOffset()const { return 0; } bool HistogramView::isIndexHidden(const QModelIndex &index)const { return true; } QRegion HistogramView::visualRegionForSelection(const QItemSelection &selection)const { return QRegion(); } //选项的更新 void HistogramView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { viewport()->update(); //更新数据 } //当鼠标在按下的时候调用setSelection函数,确定鼠标点击点所在的区域,设置选择项 void HistogramView::mousePressEvent(QMouseEvent *event) { QAbstractItemView::mousePressEvent(event); //视图层的鼠标点击事件获取 qDebug()<<"mouse"; setSelection(QRect(event->pos().x(), event->pos().y(), 1, 1), QItemSelectionModel::SelectCurrent); //获取当前选择的那个区域 } //返回选择到的数值的区域 QRegion HistogramView::itemRegion(QModelIndex index) { QRegion region; if(index.column() == 1) //第二列 { region = MRegionList[index.row()]; //得到点击到的当前行号对应的男生数值区域 } if(index.column() == 2) //第三列 { region = FRegionList[index.row()]; //得到点击到的当前行号对应的女生数值区域 } if(index.column() == 3) //第四列 { region = SRegionList[index.row()]; //得到点击到的当前行号对应的退休生数值区域 } return region; } //设置选择的区域 void HistogramView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) { int rows = model()->rowCount(rootIndex()); int columns = model()->columnCount(rootIndex()); QModelIndex selectedIndex; for (int row=0; row<rows; ++row) { for (int column=1; column<columns; ++column) { QModelIndex index=model()->index(row, column, rootIndex()); //得到选择中的位置的索引 QRegion region=itemRegion(index); //得到这个区域 if (!region.intersected(rect).isEmpty()) //没有重合的部分 selectedIndex = index; } } if(selectedIndex.isValid()) //里面的数据不为空 selections->select(selectedIndex, command); else { qDebug()<<"noindex"; QModelIndex noIndex; //空的索引 selections->select(noIndex, command); } } QModelIndex HistogramView::indexAt(const QPoint &point)const { QPoint newPoint(point.x(),point.y()); QRegion region; foreach(region,MRegionList) // 男 列 { if (region.contains(newPoint)) { int row = MRegionList.indexOf(region); QModelIndex index = model()->index(row,1,rootIndex()); return index; } } foreach(region,FRegionList) // 女 列 { if (region.contains(newPoint)) { int row = FRegionList.indexOf(region); QModelIndex index = model()->index(row,2,rootIndex()); return index; } } foreach(region,SRegionList) // 合计 列 { if (region.contains(newPoint)) { int row = SRegionList.indexOf(region); QModelIndex index = model()->index(row,3,rootIndex()); return index; } } return QModelIndex(); }
main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
3、效果展示
没错,我就是信管专业的,就是信息管理与信息系统
时间: 2024-10-12 15:09:41