zoukankan      html  css  js  c++  java
  • Qt5模型/视图结构-视图(View)

    实现自定义的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:QTCH803uild-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开发及实例》

  • 相关阅读:
    一个简单XQuery查询的例子
    《Microsoft Sql server 2008 Internals》读书笔记第七章Special Storage(1)
    《Microsoft Sql server 2008 Internals》读书笔记第八章The Query Optimizer(4)
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(4)
    SQL Server中SMO备份数据库进度条不显示?
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(5)
    《Microsoft Sql server 2008 Internal》读书笔记第七章Special Storage(3)
    《Microsoft Sql server 2008 Internal》读书笔记第八章The Query Optimizer(2)
    省市三级联动的DropDownList+Ajax的三种框架(aspnet/Jquery/ExtJs)示例
    FireFox意外崩溃时的手工恢复命令
  • 原文地址:https://www.cnblogs.com/Manual-Linux/p/9679342.html
Copyright © 2011-2022 走看看