实现自定义的View,可继承自QAbstractItemView类,对所需的纯虚函数进行重定义与实现,对于QAbstractItemView类中的纯虚函数,在子类中必须进行重定义,但不一定要实现,可根据需要选择实现。

DEMO

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H #include <QMainWindow>
#include <QStandardItem>
#include <QTableView>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QSplitter>
#include "histogramview.h" class MainWindow : public QMainWindow
{
Q_OBJECT public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void creatAction();
void creatMenu();
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

histogramview.h

#ifndef HISTOGRAMVIEW_H
#define HISTOGRAMVIEW_H #include <QAbstractItemView>
#include <QItemSelectionModel>
#include <QRegion>
#include <QMouseEvent>
#include <QList> //自定义HistogramView类继承自QAbstractItemView类,用于对表格数据进行柱状图显示
class HistogramView:public QAbstractItemView
{
Q_OBJECT
public:
HistogramView(QWidget *parent=0);
//虚函数的声明
//QAbstractItemView类中的纯虚函数,这些纯虚函数不一定要实现,可以根据
//需要选择性的实现,但一定要声明
QRect visualRect(const QModelIndex &index) const;
void scrollTo(const QModelIndex &index,ScrollHint hint=EnsureVisible);
//当鼠标在视图中单击或位置发生改变时触发,它返回鼠标所在点的QModelIndex值,若鼠标
//处在某个数据项的区域中,则返回此数据的Index值,否则返回一个空的Index
QModelIndex indexAt(const QPoint &point) const;
//为selections赋初值
void setSelectionModel(QItemSelectionModel *selectionModel);
QRegion itemRegion(QModelIndex index);
void paintEvent(QPaintEvent *);
//柱状统计图可以被鼠标单击选择,选中后以不同的方式显现
void mousePressEvent(QMouseEvent *event);
protected slots:
//当数据项发生改变时,此槽函数将响应
void selectionChanged(const QItemSelection &selected,const QItemSelection &deselected);
//当模型中的数据发生变更时,此槽函数响应
void dataChanged(const QModelIndex &topLeft,
const QModelIndex &bottomRight);
protected:
//虚函数声明
QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction,
Qt::KeyboardModifiers modifiers);
int horizontalOffset() const;
int verticalOffset() const;
bool isIndexHidden(const QModelIndex &index) const;
//将位于QRect内的数据项按照SelectionFlags(描述被选择的数据项以何种方式进行更新)
//指定的方式进行更新。
void setSelection(const QRect &rect,QItemSelectionModel::SelectionFlags flags);
QRegion visualRegionForSelection(const QItemSelection &selection) const;
private:
QItemSelectionModel *selections; //用于保存与视图选择项相关的内容
QList<QRegion> MRegionList; //用于保存其中某一类型柱状图的区域范围,而每个区域是QList中的一个值
QList<QRegion> FRegionList;
QList<QRegion> SRegionList;
}; #endif // HISTOGRAMVIEW_H

mainwindow.cpp

#include "mainwindow.h"
#include <QFileDialog>
#include <QFile>
#include <QTextStream>
#include <QStringList> MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
creatAction();
creatMenu();
setupModel();
setupView();
setWindowTitle(tr("View Example"));
resize(600,600);
} MainWindow::~MainWindow()
{ } void MainWindow::creatAction()
{
openAct=new QAction(tr("打开"),this);
connect(openAct,SIGNAL(triggered(bool)),
this,SLOT(slotOpen()));
} void MainWindow::creatMenu()
{
fileMenu=new QMenu(tr("文件"),this);
fileMenu->addAction(openAct);
menuBar()->addMenu(fileMenu);
}
//新建一个model,并设置表头数据
void MainWindow::setupModel()
{
model=new QStandardItemModel(4,4,this);
model->setHeaderData(0,Qt::Horizontal,tr("部门"));
model->setHeaderData(1,Qt::Horizontal,tr("男"));
model->setHeaderData(2,Qt::Horizontal,tr("女"));
model->setHeaderData(3,Qt::Horizontal,tr("退休"));
}
void MainWindow::setupView()
{
/*
table=new QTableView; //新建一个QTableView
table->setModel(model); //为QTableView对象设置相同的Model
QItemSelectionModel *selectionModel=new QItemSelectionModel(model);
table->setSelectionModel(selectionModel);
//连接选择模型的selectionModel()信号与QTabelView对象的selectionChanged()槽函数
//以便使自定义的HistogramView对象中的选择变化能够反映到QTabelView对象的显示中
connect(selectionModel,SIGNAL(selectionChanged(QItemSelection,
QItemSelection)),
table,SLOT(selectionChanged(QItemSelection,
QItemSelection)));
splitter=new QSplitter;
splitter->setOrientation(Qt::Vertical);
splitter->addWidget(table);
setCentralWidget(splitter);
*/ splitter=new QSplitter;
splitter->setOrientation(Qt::Vertical); histogram=new HistogramView(splitter); //新建一个Histogram对象
histogram->setModel(model); //为HistogramView对象设置相同的Model table=new QTableView;
table->setModel(model); QItemSelectionModel *selectionModel=new QItemSelectionModel (model);
table->setSelectionModel(selectionModel);
histogram->setSelectionModel(selectionModel); //新建的QItemSelectionModel
//对象作为QTableView对象和HistogramView
//对象使用的选择模型 splitter->addWidget(table);
splitter->addWidget(histogram); setCentralWidget(splitter); //连接槽函数,以便使QTableView对象中的选择变化能够反映到自定义的HistogramView对象的显示中
connect(selectionModel,SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
table,SLOT(selectionChanged(QItemSelection,QItemSelection)));
connect(selectionModel,SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
histogram,SLOT(selectionChanged(QItemSelection,QItemSelection))); }
//slotOpne()槽函数完成打开标准文件对话框
void MainWindow::slotOpen()
{
QString name;
name=QFileDialog::getOpenFileName(this,"打开",".","histogram files(*.txt)"); if(!name.isEmpty())
{
openFile(name);
}
}
//openFile()函数完成打开所选的文件的内容
void MainWindow::openFile(QString path)
{
if(!path.isEmpty())
{
QFile file(path);
if(file.open(QFile::ReadOnly | QFile::Text))
{
QTextStream stream(&file);
QString line;
model->removeRows(0,model->rowCount(QModelIndex()),
QModelIndex());
int row=0;
do
{
line=stream.readLine();
if(!line.isEmpty())
{
model->insertRows(row,1,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++; } }while(!line.isEmpty());
file.close();
}
} //end if(!path.isEmpty())
}

histogramview.cpp

#include "histogramview.h"
#include <QPainter> HistogramView::HistogramView(QWidget *parent):QAbstractItemView(parent)
{ }
//paintEvent()函数完成柱状统计图绘制的工作
void HistogramView::paintEvent(QPaintEvent *)
{
//以viewport()作为绘图设备新建一个QPainter对象
QPainter painter(viewport());
painter.setPen(Qt::black);
int x0=40;
int y0=250;
/*完成了x,y坐标轴的绘制,并标注坐标轴的变量*/
//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=0;i<5;i++)
{
painter.drawLine(-1,-i*50,1,-i*50);
painter.drawText(-20,-i*50,tr("%1").arg(i*5));
}
//x轴
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(rootIndex());row++)
{
QModelIndex index=model()->index(row,0,rootIndex());
QString dep=model()->data(index).toString();
painter.drawText(posD,y0+20,dep);
posD+=50;
}
/*完成了表格第1列数据的柱状统计图的绘制*/
//男
int posM=x0+20;
MRegionList.clear();
for(row=0;row<model()->rowCount(rootIndex());row++)
{
QModelIndex index=model()->index(row,1,rootIndex());
int male=model()->data(index).toDouble();
int width=10;
//使用不同画刷颜色区别选中与未被选中的数据项
if(selections->isSelected(index))
{
//Qt::Dense3Pattern是QBrush style
//如果被选中,则画刷的style改变
painter.setBrush(QBrush(QColor(91,75,0,255),Qt::Dense3Pattern));
}
else
{
painter.setBrush(Qt::blue);
}
//根据当前数据项的值按照比例绘制一个方形表示此项数据
painter.drawRect(QRect(posM,y0-male*10,width,male*10)); QRegion regionM(posM,y0-male*10,width,male*10);
//将此数据所占据的区域保存到MRegionList列表中,为后面的数据项做准备
MRegionList.insert(row,regionM);
posM+=50;
} //end for(row=0;row<model()->rowCount(rootIndex());row++) /*完成了表格第2列数据的柱状统计图绘制*/
//女
int posF=x0+30;
FRegionList.clear();
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))
{
painter.setBrush(QBrush(Qt::red,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.insert(row,regionF);
posF+=50;
} //end for(row=0;row<=model()->rowCount(rootIndex());row++)
/*完成了表格第3列数据的柱状统计图的绘制*/
//退休
int posS=x0+40;
SRegionList.clear();
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))
{
painter.setBrush(QBrush(Qt::green,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);
SRegionList.insert(row,regionS);
posS+=50;
} //end for(row=0;row<=model()->rowCount(rootIndex());row++)
}
//dataChanged函数实现当model中的数据更改时,调用绘图设备的update()函数
//进行更新,反映数据的变化
void HistogramView::dataChanged(const QModelIndex &topLeft,
const QModelIndex &bottomRight)
{
QAbstractItemView::dataChanged(topLeft,bottomRight);
viewport()->update();
}
//setSelectionModel()函数为selections赋初值
void HistogramView::setSelectionModel(QItemSelectionModel *selectionModel)
{
selections=selectionModel;
}
//selectionChanged()函数中完成当数据项发生变化时调用update()函数
//重绘绘图设备即可工作
void HistogramView::selectionChanged(const QItemSelection &selected,
const QItemSelection &deselected)
{
viewport()->update();
}
//鼠标按下事件函数mousePressEvent(),在调用setSelection()函数时确定鼠标单击
//点是否在某个数据项的区域内,并设置选择项
void HistogramView::mousePressEvent(QMouseEvent *event)
{
QAbstractItemView::mousePressEvent(event);
setSelection(QRect(event->pos().x(),event->pos().y(),1,1),
QItemSelectionModel::SelectCurrent);
}
void HistogramView::setSelection(const QRect &rect,
QItemSelectionModel::SelectionFlags flags)
{
int rows=model()->rowCount(rootIndex()); //获取总行数
int columns=model()->columnCount(rootIndex()); //获取总列数 //用于保存被选中的数据项的Index值,此处只实现了用鼠标单击选择,而没有实现
//鼠标拖曳框选,因此,鼠标动作只可能选中一个数据项。若实现框选,则可使用
//QModelIndexList来保存所有被选中的数据项的Index值
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); //返回指定index的数据项所占用的区域
if(!region.intersected(rect).isEmpty())
selectedIndex=index;
}
}
if(selectedIndex.isValid())
selections->select(selectedIndex,flags);
else
{
QModelIndex noIndex;
selections->select(noIndex,flags);
}
}
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,FRegionList)
{
if(region.contains(newPoint))
{
int row=FRegionList.indexOf(region);
QModelIndex index=model()->index(row,2,rootIndex());
return index;
}
}
return QModelIndex();
}
QRect HistogramView::visualRect(const QModelIndex &index)const{}
void HistogramView::scrollTo(const QModelIndex &index,ScrollHint){}
QModelIndex HistogramView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers){}
int HistogramView::horizontalOffset()const{}
int HistogramView::verticalOffset()const{}
bool HistogramView::isIndexHidden(const QModelIndex &index)const{}
QRegion HistogramView::visualRegionForSelection(const QItemSelection & selection)const{}
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;
}

main.cpp

#include "mainwindow.h"
#include <QApplication> int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show(); return a.exec();
}

注意.pro文件如下

#-------------------------------------------------
#
# Project created by QtCreator 2018-09-05T19:29:45
#
#------------------------------------------------- QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = CH803
TEMPLATE = app DEFINES += QT_DEPRECATED_WARNINGS #新增加的 SOURCES += main.cpp\
mainwindow.cpp \
histogramview.cpp HEADERS += mainwindow.h \
histogramview.h

在该目录下新建文件histogram.txt

E:\QT\CH803\build-CH803-Desktop_Qt_5_6_2_MinGW_32bit-Debug

内容如下

一部,12,3,5
二部,16,4,0
三部,18,4,2
四部,10,3,1
五部,11,4,3
六部,12,2,4
七部,14,3,5
八部,9,1,1

运行效果如下



备注

这个程序里有几个函数我还是没搞懂,不太清楚其中的逻辑

void HistogramView::setSelection(const QRect &rect,
QItemSelectionModel::SelectionFlags flags)
QModelIndex HistogramView::indexAt(const QPoint &point) const

参考资料《Qt5开发及实例》

Qt5模型/视图结构-视图(View)的更多相关文章

  1. Qt 模型/视图结构

    MVC是一种与用户界面相关的设计模式.通过使用此模型,可以有效地分离数据和用户界面.MVC设计模式包含三要素:表示数据的模型(Model).表示用户界面的视图(View)和定义了用户在界面上的操作控制 ...

  2. C#-MVC基础-模型(Model)、视图(View)和控制器(Controller)

    搜狗百科:http://baike.sogou.com/v25227.htm?fromTitle=MVC MVC全名是Model View Controller,是软件工程中的一种软件架构模式,把软件 ...

  3. 38.Qt模型/视图结构

    1.模型/视图类 2.模型 3.视图 4.代理 1 模型/视图类 InterView框架提供了一些可以直接使用的模型类和视图类,如QStandardModel类,QDirModel类,QStringL ...

  4. Odoo10学习笔记三:模型(结构化的应用数据)、视图(用户界面设计)

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/11189263.html 一:模型 [Odoo中,一切皆模型,连视图都是模型.Odoo将各种数据,如:权限数据 ...

  5. Django框架——基础之视图系统(View.py)

    Django框架之View.py(视图文件) 1. 视图简介 视图层是Django处理请求的核心代码层,我们大多数Python代码都集中在这一层面. 它对外接收用户请求,对内调度模型层和模版层,统合数 ...

  6. SAP CRM 树视图(TREE VIEW)

    树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...

  7. Android应用程序窗口(Activity)的视图对象(View)的创建过程分析

    从前文可知道,每一个Activity组件都有一个关联的Window对象,用来描述一个应用程序窗口.每一个应用程序窗口内部又包含有一个View对象,用来描述应用程序窗口的视图.应用程序窗口视图是真正用来 ...

  8. 深入分析MFC文档视图结构(项目实践)

    k_eckel:http://www.mscenter.edu.cn/blog/k_eckel 文档视图结构(Document/View Architecture)是MFC的精髓,也是Observer ...

  9. Swift - iOS中各种视图控制器(View Controller)的介绍

    在iOS中,不同的视图控制器负责不同的功能,采用不同的风格向用户呈现信息.下面对各个视图控制器做个总结: 1,标准视图控制器 - View Controller 这个控制器只是用来呈现内容.通常会用来 ...

随机推荐

  1. word2010自定义的多级列表编号变成黑块的解决办法

    首先,看图说话 是的,当我保存Word再打开之后,我辛辛苦苦(没错,小白有罪,调来调去真辛苦)搞得多级列表编号变成了黑块,默默无言,只有泪千行,还好有万能的Google. 解决办法: 将光标移到黑块的 ...

  2. MQ选型对比RabbitMQ RocketMQ ActiveMQ Kafka(外加redis对比及其实现)

    rocketmq 4.3开始支持事务https://www.cnblogs.com/hzmark/p/rocket_txn.html 参考:rabbitMQ.activeMQ.zeroMQ.Kafka ...

  3. [翻译]使用VH和VW实现真正的流体排版

    前言 不像响应式布局,通过media query,设置几个变化点来适配,流体排版通过调整大小,适配所有设备宽度.这个方法可以使我们开发的网页,在几乎所有屏幕尺寸上都可以使用.但出于一些原因,它的使用率 ...

  4. 排它平方数|2013年蓝桥杯A组题解析第二题-fishers

    排它平方数 小明正看着 203879 这个数字发呆. 原来,203879 * 203879 = 41566646641 这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是 ...

  5. Forms Authentication and Role based Authorization: A Quicker, Simpler, and Correct Approach

    https://www.codeproject.com/Articles/36836/Forms-Authentication-and-Role-based-Authorization Problem ...

  6. ProgrammingError: You must not use 8-bit bytestrings...

    问题出现: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit byte ...

  7. 简单的栈溢出demo

    Code package startnow; /** * @auther draymonder */ public class StackOverFlowTest { public static vo ...

  8. hihoCoder week2 Trie树

    题目链接 https://hihocoder.com/contest/hiho2/problems 字典树 #include <bits/stdc++.h> using namespace ...

  9. Linux/shell: remove adjacent similar patterns

    cat > temp004AA1abcAA2AA3abcAA4abcAA5AA6 awk 'BEGIN {pre=0; str="";} { if(NR==1){     i ...

  10. R语言之正则表达式

    常见与正则表达式相关的函数: grep(pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE, fixed = FALSE, use ...