Qt模型/视图原理(4):自定义视图(QAbstractItemView)

Qt模型/视图原理(4):自定义视图(QAbstractItemView)

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

自定义视图的基本原则如下
1)、视图需要自行绘制,通常在paintEvent()函数内完成,所以除了必须实现的纯虚函数外,paintEvent()也应重新实现。另外若需要对单元格进行重新绘制、更新滚动条等,还需要重新实现resizeEvent()函数。
2)、自定义视图需要完成显示的单元格的大小和位置的计算、单元格轮廓线的绘制、滚动的计算、对单元格的选择作出处理、若有必要还需要绘制标头。
3)、另外需要记住的是视图就是一个QFrame,也就是说直接使用show()显示视图,那么视图只是一个什么也没有的窗口而已,窗口中的内容需要由程序员设计,也就是说你也可以完全不继承QAbstractItemView类,而子类化QFrame类来实现视图中内容的绘制,当然这样会失去对QAbstractItemView类中由Qt已实现的内部函数的使用。

QAbstractItemView类中的纯虚函数的原型如下
在这里插入图片描述
在这里插入图片描述

示例8.11为最小的自定义视图实现,也就是说以下代码实现的视图功能并不完善。完整的实现需要比较复杂的计算量,以下代码主要是要让读者明白,视图究竟用来做什么,做了什么。从而加深对模型/视图结构的理解。作为最小实现,本示例只处理单元格轮廓线的绘制、单元格中数据项的绘制,以及简单的选择操作
示例8.11的基本规则:使用paintEvent()函数完成由visualRect()函数返回的矩形的轮廓线及其数据项的绘制,其中数据项调用委托绘制。

示例8.11:简单的自定义视图
//m.h文件的内容
#ifndef M_H
#define M_H
#include<QtWidgets>

class V:public QAbstractItemView{
public:
//1、以下函数用于计算项目所占据的矩形(即位置和大小)
QRect visualRect(const QModelIndex &index) const{
//该函数在初次运行时便会由Qt调用,调用次数依模型而定,本例3*3的表格模型,
//该函数会被调用18次。参数index包含模型的索引,index会在调用时循环传递。
//比如对于本例,第一次调用时的索引为(0,0),第二次为(0,1),第3次为(0,2)…

	//计算项目的矩形:项目大小始终为(110,33),位置随索引而不同。
	return QRect(index.column()*110,index.row()*33+20,110,33);		}

//2、以下函数返回鼠标光标所在位置的项目的索引
QModelIndex indexAt(const QPoint &point) const{ //该函数在点击鼠标时Qt会调用。
//参数point包含了鼠标光标的坐标位置(视图坐标)
int r=(point.y()-20)/33; //计算光标位于哪一行。
int c=point.x()/110; //计算光标位于哪一列。
return model()->index(r,c); } //返回该项目的索引。

//3、以下两个函数主要用于处理对项目的选择,当选择视图中的项目时,Qt才会调用他们。
//当不需要选择项目时,以下两个函数可以不用实现。
void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) {
//参数rect包含了所选项目的矩形(位置和大小,使用视图坐标)
//参数flags包含了选择项目时的选择标志。
int r=(rect.y()-20)/33; //计算选中的是哪一行。
int c=rect.x()/110; //计算选中的是哪一列。
selectionModel()->select(model()->index(r,c),flags); } //选择所选中的索引。

QRegion visualRegionForSelection(const QItemSelection &amp;s) const {
		//此函数用于计算所有被选择的项目占据的区域(即位置和大小)。
		//参数s包含了所选择的项目的范围。
		return QRegion();    }

//4、以下函数用于计算视图的滚动,本例是最小实现,不需要滚动,所以不需要实现以下3个函数。
int horizontalOffset() const{ return 0; }
int verticalOffset() const { return 0; }
void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible){}

//5、本示例不需要隐藏项目,所以以下函数直接返回0即可。
bool isIndexHidden(const QModelIndex &index) const{ return 0; }

//6、以下函数用于处理键盘按键(比如按下左键应返回左侧的项目索引等),本示例不处理键盘按键,
//所以不需要实现。
QModelIndex moveCursor(CursorAction cursorAction ,Qt::KeyboardModifiers modifiers){
return QModelIndex(); }

//7、以下函数是核心,用于绘制视图的外观,也就是说若没有以下函数,则视图什么也不会显示。

    	void paintEvent(QPaintEvent *e){
        	QPainter pt(viewport());   //在视口上绘制图形
    	//使用QAbstractItemView::viewOptions()获取需要绘制的图形的信息(此步骤比较重要)
        	QStyleOptionViewItem po=viewOptions();
    //循环遍历模型的大小。
    		for(int r=0;r&lt;model()-&gt;rowCount();r++)
        	for(int c=0;c&lt;model()-&gt;columnCount();c++){
        		QModelIndex i=model()-&gt;index(r,c);
        		QRect rect=visualRect(i);        //获取索引i所指项目的矩形(位置和大小)
        		po.rect=visualRect(i);
        //处理项目被选择的情形
        		if(selectionModel()-&gt;isSelected(i)){  po.state |= QStyle::State_Selected;}
        //使用代理绘制数据项(即项目),这里也可使用自定义的代理(若已添加)
         		itemDelegate()-&gt;paint(&amp;pt,po,i);
        //以下代码用于绘制视图单元格的轮廓线。
       		pt.save();
        		pt.setPen(QPen(QColor(111,1,1)));  //创建画笔。
        		pt.drawLine(rect.bottomLeft(),rect.bottomRight());
        		pt.drawLine(rect.bottomRight(),rect.topRight());
        		pt.restore(); 		}  //for结束
    		}  //paintEvent结束
};

class B:public QWidget{    Q_OBJECT
public:    QStandardItemModel *d;    V *pv;
    B(QWidget *p=0):QWidget(p){
   		d=new QStandardItemModel(3,3);
    		V* pv=new V;    		//使用自定义的视图
	//向模型中添加数据
    		d-&gt;setData(d-&gt;index(0,0),"AAA");    d-&gt;setData(d-&gt;index(0,1),"BBB");
    		d-&gt;setData(d-&gt;index(1,0),"CCC");    d-&gt;setData(d-&gt;index(1,2),"DDD");
    		d-&gt;setData(d-&gt;index(1,1),"EEE");    d-&gt;setData(d-&gt;index(2,0),"FFF");
    		d-&gt;setData(d-&gt;index(1,1),QIcon("F:/1i.png"),Qt::DecorationRole);

//向视图中添加标签,以用于视图的标头,以下代码主要演示视图还可以像使用一个QFrame那样使用。
    		QLabel *pp=new QLabel("111",pv);
    		pp-&gt;setAutoFillBackground(1);  //使标签不透明。
    		pp-&gt;setAlignment(Qt::AlignCenter);   pp-&gt;resize(111,20);
    		QLabel *pp1=new QLabel("222",pv);    pp1-&gt;setAutoFillBackground(1);
    		pp1-&gt;setAlignment(Qt::AlignCenter);  pp1-&gt;resize(111,20);   pp1-&gt;move(111,0);
    		QLabel *pp2=new QLabel("333",pv);	pp2-&gt;setAutoFillBackground(1);
    		pp2-&gt;setAlignment(Qt::AlignCenter); 	pp2-&gt;resize(111,20);	pp2-&gt;move(222,0);

    		//pv-&gt;setItemDelegate(pt);   //也可以添加自定义代理,以使用自定义代理绘制数据项。
    		pv-&gt;setModel(d);    pv-&gt;resize(333,222);    pv-&gt;show();         }	
};
#endif // M_H

//m.cpp文件内容
#include "m.h"
int main(int argc, char *argv[]){ QApplication app(argc,argv); B w;  return app.exec(); }

运行结果及说明见图8-37
在这里插入图片描述

本文作者:黄邦勇帅(原名:黄勇)

在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以通过继承 QTreeView 类来自定义文件列表树视图。 首先,创建一个新的类(例如 CustomTreeView),并将其继承自 QTreeView。然后,在类的构造函数中进行一些初始化设置,如设置文件模型和根节点。 接下来,你可以重写某些父类方法来实现自定义的行为。例如,你可以重写 data() 方法来返回每个单元格的自定义数据,或者重写 dropEvent() 方法来实现拖放操作。 以下是一个简单的示例代码,演示如何自定义文件列表树视图: ```cpp #include <QTreeView> #include <QFileSystemModel> class CustomTreeView : public QTreeView { public: CustomTreeView(QWidget *parent = nullptr) : QTreeView(parent) { // 创建文件模型 QFileSystemModel *fileModel = new QFileSystemModel(this); fileModel->setRootPath("/"); // 设置根节点 QModelIndex rootIndex = fileModel->index("/"); setModel(fileModel); setRootIndex(rootIndex); // 设置其他视图选项(可选) setSelectionMode(QAbstractItemView::ExtendedSelection); setDragEnabled(true); setAcceptDrops(true); } QVariant data(const QModelIndex &index, int role) const override { if (role == Qt::DisplayRole) { // 返回自定义显示数据 return "Custom Data"; } return QTreeView::data(index, role); } void dropEvent(QDropEvent *event) override { // 实现拖放操作的逻辑 // ... QTreeView::dropEvent(event); } }; ``` 然后,你可以在主窗口或其他地方使用 CustomTreeView 类来创建自定义的文件列表树视图: ```cpp #include <QMainWindow> #include <QVBoxLayout> class MainWindow : public QMainWindow { public: MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) { QWidget *centralWidget = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout(centralWidget); CustomTreeView *treeView = new CustomTreeView(this); layout->addWidget(treeView); setCentralWidget(centralWidget); } }; ``` 这只是一个简单的示例,你可以根据你的需求进一步自定义文件列表树视图的行为和外观。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值