Qt之视图(View)

本文介绍了如何创建一个自定义的HistogramView,该视图继承自QAbstractItemView,并实现了如visualRect、scrollTo、indexAt等纯虚函数。通过鼠标事件处理选择和绘制柱状图,以及响应数据变化和选择变化的槽函数。示例代码展示了柱状图的绘制和数据绑定,以及与QTableView的集成。
摘要由CSDN通过智能技术生成

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

1、运行效果

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

2、具体代码

​​histogramview.h​​

#ifndef HISTOGRAMVIEW_H
#define HISTOGRAMVIEW_H

#include <QAbstractItemView>
#include <QItemSelectionModel>
#include <QRegion>
#include <QMouseEvent>

class HistogramView : public QAbstractItemView
{
    Q_OBJECT
public:
    HistogramView(QWidget *parent = 0);
    //虚函数声明
    QRect visualRect(const QModelIndex &index) const;  //(a)
    void scrollTo(const QModelIndex &index,ScrollHint hint = EnsureVisible);
    QModelIndex indexAt(const QPoint &point) const;  //(b)
    //为selections赋初值
    void setSelectionModel(QItemSelectionModel *selectionModel);
    QRegion itemRegion(QModelIndex index);
    void paintEvent(QPaintEvent *);
    void mousePressEvent(QMouseEvent *event);  //(c)

protected slots:
    void selectionChanged(const QItemSelection &selected,const QItemSelection &deselected);  //(d)
    void dataChanged(const QModelIndex &topLeft,const QModelIndex &bottomRight);  //(e)

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 flags);  //(f)
    QRegion visualRegionForSelection(const QItemSelection &selection) const;

private:
    QItemSelectionModel *selections;  //(g)
    QList<QRegion> MRegionList;  //(h)
    QList<QRegion> FRegionList;
    QList<QRegion> SRegionList;

};

#endif // HISTOGRAMVIEW_H

其中:

(a) visualRect()、scrollTo()、indexAt()、moveCursor()、horizontalOffset()、verticelOffset()、isIndexHidden()、setSelection()和visualRegionSelection():QAbstractItemView类中的纯虚函数。这些纯虚函数不一定都要实现,可以根据需要选择性地实现,但是一定要声明。

(b) QModelIndex indexAt(const QPoint &point) const:当鼠标在视图中单击或位置发生改变时被触发,它返回鼠标所在点的QModelIndex值。若鼠标处在某个数据项的区域中,则返回此数据项的Index值,否则返回一个空的Index。

© void mousePressEvent(QMouseEvent *event):柱状统计图可以被鼠标单击选择,选中则以不同的方式显示。

(d) void selectionChanged(const QItemSelection &selected,const QItemSelection &deselected):当数据项选择发生变化是,此槽函数将响应。

(e) void dataChanged(const QModelIndex &topLeft,const QModelIndex &bottomRight):当模型中的数据发生变更时,此槽函数将响应。

(f) void setSelection(const QRect &rect,QItemSelectionModel::SelectionFlags flags):将位于QRect内的数据项安装SelectionFlags(描述被选择的数据项以何种方式进行更新)指定的方式进行更新。QItemSelectionModel类提供多种可用的SelectionFlags,常用的有​​QItemSelectionModel::select​​​、​​QItemSelectionModel::Current​​​等。

(g) QItemSelectionModel ​​*​​selections:用于保存与视图选择项相关的内容。

==(h) QList MRegionList ==:用于保存其中某一类型柱状图的区域范围,而每个区域是QList中的一个值。

​​histogramview.cpp​​

#include "histogramview.h"
#include <QPainter>

HistogramView::HistogramView(QWidget *parent) : QAbstractItemView(parent)
{

}

//paintEvent()函数具体完成柱状统计图的绘制工作
void HistogramView::paintEvent(QPaintEvent *)
{
    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("人数"));
    //x坐标轴
    painter.drawLine(x0,y0,540,250);
    painter.drawLine(538,248,540,250);
    painter.drawLine(540,250,538,252);
    painter.drawText(545,250,tr("部门"));
    /*完成x轴坐标值的绘制*/
    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;
    }
    /*完成了表格第一列数据的柱状统计图的绘制*/
    //男
    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))  //(b)
            painter.setBrush(QBrush(Qt::blue,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.insert(row,regionM);  
        posM+=50;
    }
    /*完成了表格第一列数据的柱状统计图的绘制*/
    //女
    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;
    }
    /*完成了表格第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;

    }
}

void HistogramView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
    QAbstractItemView::dataChanged(topLeft,bottomRight);
    viewport()->update();
}

void HistogramView::setSelectionModel(QItemSelectionModel *selectionModel)
{
    selections=selectionModel;
}

void HistogramView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    viewport()->update();
}

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());
    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,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, SRegionList)
    {
       if(region.contains(newPoint))
       {
           int row=FRegionList.indexOf(region);
           QModelIndex index=model()->index(row,3,rootIndex());
           return index;
       }
    }

    return QModelIndex();
}

QRect HistogramView::visualRect(const QModelIndex &index) const
{

}

void HistogramView::scrollTo(const QModelIndex &index, ScrollHint hint)
{

}

QModelIndex HistogramView::moveCursor(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;
}

​​mainwindow.h​​

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStandardItemModel>
#include <QTableView>
#include <QMenuBar>
#include <QAction>
#include <QSplitter>
#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​​

#include "mainwindow.h"
#include <QItemSelectionModel>
#include <QFileDialog>
#include <QFile>
#include <QTextStream>
#include <QStringList>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    createAction();
    createMenu();
    setupModel();
    setupView();
    setWindowTitle(tr("View Example"));
    resize(600,600);
}

MainWindow::~MainWindow()
{

}

void MainWindow::createAction()
{
    openAct = new QAction(tr("打开"),this);
    connect(openAct,SIGNAL(triggered(bool)),this,SLOT(slotOpen()));
}

void MainWindow::createMenu()
{
    fileMenu = new QMenu(tr("文件"),this);
    fileMenu->addAction(openAct);
    menuBar()->addMenu(fileMenu);
}

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()
{
    splitter = new QSplitter;
    splitter->setOrientation(Qt::Vertical);
    histogram=new HistogramView(splitter);
    histogram->setModel(model);
    table = new QTableView;
    table->setModel(model);
    QItemSelectionModel *selectionModel = new QItemSelectionModel(model);
    table->setSelectionModel(selectionModel);
    histogram->setSelectionModel(selectionModel);
    splitter->addWidget(table);
    splitter->addWidget(histogram);
    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 MainWindow::slotOpen()
{
    QString name = QFileDialog::getOpenFileName(this,"打 开",".","histogram files(*.txt)");
    if(! name.isEmpty())
    {
        openFile(name);
    }
}

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(",");
                    //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();
        }
    }
}

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值