QTreeView的使用总结1

一、概述

Qt中 treeview的典型使用方法是model/view。这里不介绍model、view、delegate的工作方式。

model 、delegate与treeview的关联过程如下:

 

ui.treeView->setModel( pModel );
ui.treeView->setItemDelegate( pDelegate );

 

 

 

 

 

二、设置TreeView的头部信息

1、设置表头

      方法一:void QStandardItemModel::setHorizontalHeaderLabels( const QStringList & labels );

              参数labels指定一个QStringList对象,该对象中的每个字符串对应一个列的名字。

      方法二:void QStandardItemModel::setHorizontalHeaderItem(int column, QStandardItem * item);

              参数 column指定列的索引,item指定列的内容

例子:分别使用上述两种方法设置TreeView头部信息

方法一:

 

QStringList ColumnStringList;
	ColumnStringList << QStringLiteral("车库") << QStringLiteral("信息");
	model->setHorizontalHeaderLabels( QStringList() << QStringLiteral("车库")<< QStringLiteral("信息") );
	QStandardItem* pColumnItem = model->horizontalHeaderItem(0);
	pColumnItem->setIcon( QIcon(":/TreeView_T/Resources/qt-logo.png") );
	pColumnItem->setToolTip(QStringLiteral("这是第一列") );

	pColumnItem = model->horizontalHeaderItem(1);
	pColumnItem->setIcon(QIcon(":/TreeView_T/Resources/qt-logo.png") );
	pColumnItem->setToolTip(QStringLiteral("这是第二列"));

方法二:

 

 

QStandardItem* pItem = new QStandardItem( QIcon(":/TreeView_T/Resources/qt-logo.png"), QStringLiteral("车库"));
	pItem->setToolTip( QStringLiteral("这是第一列"));

	QStandardItem* pItem1 = new QStandardItem( QIcon(":/TreeView_T/Resources/qt-logo.png"), QStringLiteral("信息") );
	pItem1->setToolTip( QStringLiteral("这是第二列"));

	model->setHorizontalHeaderItem( 0, pItem);
	model->setHorizontalHeaderItem( 1, pItem1);

 

2、隐藏表头

       通过QTreeView中的 header()->hide(),可以隐藏表头。

 

效果如下:

 

三、填充行与列

(1)、可以在行头部添加图标

例子:

 

QMap<QString, QIcon> m_IconMap;//存放公共图标
	QMap<QString, QIcon> m_CarportIconMap;  //车库公共图标

	//初始化图标库
	m_CarportIconMap[QStringLiteral("Port1")] = QIcon(QStringLiteral(":/cars1/Resources/cars1/3942000.ico"));
	m_CarportIconMap[QStringLiteral("Port2")] = QIcon(QStringLiteral(":/cars1/Resources/cars1/3942001.ico"));
	m_CarportIconMap[QStringLiteral("Port3")] = QIcon(QStringLiteral(":/cars1/Resources/cars1/3942002.ico"));
	m_CarportIconMap[QStringLiteral("Port4")] = QIcon(QStringLiteral(":/cars1/Resources/cars1/3942003.ico"));
	m_CarportIconMap[QStringLiteral("Port5")] = QIcon(QStringLiteral(":/cars1/Resources/cars1/3942004.ico"));

	m_IconMap[QStringLiteral("Audi")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/audi.ico") );
	m_IconMap[QStringLiteral("Bmw")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/bmw.ico") );
	m_IconMap[QStringLiteral("Buick")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/Buick.ico") );
	m_IconMap[QStringLiteral("Cadillac")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/cadillac.ico") );
	m_IconMap[QStringLiteral("Ferrari")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/ferrari.ico") );
	m_IconMap[QStringLiteral("Ford")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/ford.ico") );
	m_IconMap[QStringLiteral("Hyundai")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/hyundai.ico") );
	m_IconMap[QStringLiteral("Lexus")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/lexus.ico") );
	m_IconMap[QStringLiteral("Mazda")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/mazda.ico") );
	m_IconMap[QStringLiteral("Mercedesbenz")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/mercedesbenz.ico") );
	m_IconMap[QStringLiteral("Nissan")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/nissan.ico") );
	m_IconMap[QStringLiteral("Toyota")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/toyota.ico") );
	m_IconMap[QStringLiteral("Volkswagen")] = QIcon( QStringLiteral(":/cars_logo/Resources/cars_logo/Volkswagen.ico") );

	QStandardItem* pStandardItem = NULL;
	QStandardItem* pStandardChildItem = NULL;
	int i = 0;
	QMap<QString, QIcon>::const_iterator it1 = m_CarportIconMap.constBegin();
	for (QMap<QString, QIcon>::const_iterator it = m_IconMap.constBegin(); it != m_IconMap.constEnd(); ++it)
	{
		if (i % 3 == 0)
		{
			pStandardItem = new QStandardItem((it1 + (i / 3)).value(), (it1 + (i / 3)).key());
			model->appendRow(pStandardItem);
		}
		pStandardChildItem = new QStandardItem( it.value(), it.key());
		pStandardItem->appendRow( pStandardChildItem );
		pStandardItem->setChild( pStandardChildItem->row(),1, new QStandardItem( QString("this is %1").arg( it.key()) ));
		++i;
	}

效果如下:

 


(2)、可以在行头添加单选框
使用QStandardItem时与checkbox相关的几个函数:

       void QStandardItem::setCheckable(bool checkable);     //设置Item是否有复选框功能

       void QStandardItem::setCheckState(Qt::CheckState state);    //设置Item的复选状态

       Qt::CheckState有三种状态:Qt::Unchecked :未选中状态、Qt::PartiallyChecked:部分选中状态(层次模型中的子项有一部分处于选中状态)、Qt::Checked:选中状态

       void QStandardItem::setTristate(bool tristate);    //设置Item是否是三态的(Qt::Unchecked、Qt::PartiallyChecked、Qt::Checked)

       Qt::CheckState QStandardItem::checkState() const ;    //返回Item的复选状态

       bool QStandardItem::isCheckable() const ;     //判断Item是否是可复选的

       bool QStandardItem::isTristate() const ;     //判断Item是否是三态的

例子:

 

QStandardItem* pStandardItem = NULL;
	QStandardItem* pStandardChildItem = NULL;
	int i = 0;
	QMap<QString, QIcon>::const_iterator it1 = m_CarportIconMap.constBegin();
	for (QMap<QString, QIcon>::const_iterator it = m_IconMap.constBegin(); it != m_IconMap.constEnd(); ++it)
	{
		if (i % 3 == 0)
		{
			pStandardItem = new QStandardItem((it1 + (i / 3)).value(), (it1 + (i / 3)).key());

			//设置Item为三态
			pStandardItem->setTristate( true );

			//设置Item为部分选中状态
			pStandardItem->setCheckState( Qt::PartiallyChecked );

			model->appendRow(pStandardItem);
		}
		pStandardChildItem = new QStandardItem( it.value(), it.key());
		
		//设置Item具有单选能力
		pStandardChildItem->setCheckable( true );

		//设置Item不具有三态
		pStandardChildItem->setTristate( false );

		//设置Item为选中状态
		pStandardChildItem->setCheckState( /*Qt::PartiallyChecked*/  Qt::Checked );

		pStandardItem->appendRow( pStandardChildItem );
		pStandardItem->setChild( pStandardChildItem->row(),1, new QStandardItem( QString("this is %1").arg( it.key()) ));

		++i;
	}

效果如下:

 


 

(3)三态复选框的智能关联(如果子项全选,父级也需要全选,如果子项部分选,父级就不完全选)

 

/*
QTreeView在QStandardItemModel设置复选框后,并不是按照规则的,需要通过代码设置
三态复选框主要体现在树形控件里,如果子项目全选,父级需要全选,如果子项目部分选择,父级就是不完全选
*/
/*
item checkbox单击响应函数
*/
void MyDelegate::treeItem_CheckChanged(QStandardItem* item)
{
	if (item == nullptr)
	{
		return;
	}
	if (item->isCheckable() )
	{
		//如果item是存在复选框的,那么就进行下面的操作
		Qt::CheckState state = item->checkState(); //获取当前的选择状态
		if (item->isTristate())
		{
			//如果item是三态的,说明可以对子目录进行全选和全不选的设置
			if (state != Qt::PartiallyChecked)
			{
				//当前是选中状态,需要对其子项目设置为全选
				treeItem_CheckAllChild(item, state == Qt::Checked ? true : false);
			}
		}
		else
		{
			//说明是两态的,两态会对父级的三态有影响
			//判断兄弟节点的情况
			treeItem_CheckChildChanged( item );
		}
	}
} 

//
// \brief 递归设置所有的子项目为全选或全不选状态
// \param item 当前项目
// \param check true时为全选,false时全不选
//
void MyDelegate::treeItem_CheckAllChild(QStandardItem* item, bool check)
{
	if (item == nullptr)
	{
		return;
	}
	int rowCount = item->rowCount();
	for (int i = 0; i < rowCount; ++i )
	{
		QStandardItem* childItems = item->child( i );
		treeItem_checkAllChild_recursion( childItems, check);
	}

	if (item->isCheckable())
	{
		item->setCheckState( check ? Qt::Checked : Qt::Unchecked);
	}
}

void MyDelegate::treeItem_checkAllChild_recursion(QStandardItem* item, bool check)
{
	if (item == nullptr)
	{
		return;
	}
	int rowCount = item->rowCount();
	for (int i = 0; i < rowCount; ++i)
	{
		QStandardItem* childItems = item->child( i );
		treeItem_checkAllChild_recursion( childItems, check);
	}
	if (item->isCheckable())
	{
		item->setCheckState( check ? Qt::Checked : Qt::Unchecked );
	}
}

//
// \brief 根据子节点的改变,更改父节点的选择情况
// \param item
//
//此函数也是一个递归函数,首先要判断的是父级是否到达顶层
//,到达底层作为递归的结束,然后通过函数checkSibling判断当前的兄弟节点的具体情况
//
void MyDelegate::treeItem_CheckChildChanged(QStandardItem* item)
{
	if (nullptr == item)
	{
		return;
	}
	Qt::CheckState siblingState = checkSibling( item );
	QStandardItem* parentItem = item->parent();
	if (nullptr == parentItem)
	{
		return;
	}
	if (Qt::PartiallyChecked == siblingState)
	{
		if (parentItem->isCheckable() && parentItem->isTristate())
			parentItem->setCheckState( Qt::PartiallyChecked );
	}
	else if (Qt::Checked == siblingState)
	{
		if (parentItem->isCheckable())
			parentItem->setCheckState( Qt::Checked);
	}
	else
	{
		if (parentItem->isCheckable())
			parentItem->setCheckState( Qt::Unchecked );
	}
	treeItem_CheckChildChanged( parentItem );
}

//
// \brief 测量兄弟节点的情况,如果都选中返回Qt::Checked,都不选中Qt::Unchecked, 
// \不完全选中返回Qt::PartiallyChecked
// \param item
// \return 
Qt::CheckState MyDelegate::checkSibling(QStandardItem* item)
{
	//先通过父节点获取兄弟节点
	QStandardItem* parent = item->parent();
	if (nullptr == parent)
	{
		return item->checkState();
	}
	int brotherCount = parent->rowCount();
	int checkedCount(0), unCheckedCount( 0 );

	Qt::CheckState state;
	for (int i = 0; i < brotherCount; ++i)
	{
		QStandardItem* siblingItem = parent->child( i );
		state = siblingItem->checkState();
		if (Qt::PartiallyChecked == state)
		{
			return Qt::PartiallyChecked;
		}
		else if (Qt::Unchecked == state)
		{
			++unCheckedCount;
		}
		else
		{
			++checkedCount;
		}
		if (checkedCount > 0 && unCheckedCount > 0)
		{
			return Qt::PartiallyChecked;
		}
	}
	if (unCheckedCount > 0)
	{
		return Qt::Unchecked;
	}
	return Qt::Checked;
}

 

四、QStandardItemModel的角色控制

 

<一>、自定义角色的使用

        在MFC中,树形控件CTreeCtrl是通过SetItemData函数来对节点设置一个指针的值,这个值可以是个指针、DWORD值、自定义的标志或者自定义类型的指针。Qt的TreeView比MFC的CTreeCtrl封装的更好,其功能也更强大,以至于可以给每个节点设定非常非常多的值(只要内存足够)。QTreeView只负责显示渲染,数据都有Model来负责管理。我们可以使用setData函数来为节点设置数据。

        setData函数在Model和Item中都有,功能都一样。QStandardItemModel中setData函数的定义:

        virtual bool setData( const QModelIndex & index,   const  QVarient & value,  int role = Qt::EditRole);

QStandardItem中setData的定义是:

        virtual void setData( const QVaritant & value,  int role = Qt::UserRole + 1 );

         参数:value:是要设置的值, role是一个int型数据,Qt中把这个称为role角色,实际就是对设定值的标定,因为item可以设置许多值,这就需要一个用以区分的标志,这个区分标志就叫角色。Qt已经把经常用到的角色内容定义好了,我们可以自定义角色标志,但不要和定义好的那些标志冲突,否则会不起作用。如果显示文字就用Qt::DisplayRole,要告诉QTreeView需要改变背景颜色,就标定Qt::BackgroundRole,要改变字体就标定Qt::FontRole等等。从中可以看出,role就是一个标示,用来标定存放在item李淼的值集体用于什么功能,系统默认的role参看Qt::ItemDataRole枚举。自定义的Role,就从Qt::UserRole开始往上加。

例子:

        定义用户自定义的role:

 

#define ROLE_MARK_TYPE Qt::UserRole + 100
#define MARK_FOLDER 1
#define MARK_ITEM   2

       为Item设置数据

 

 

QStandardItem* pStandardItem = NULL;
	QStandardItem* pStandardChildItem = NULL;
	int i = 0;
	QMap<QString, QIcon>::const_iterator it1 = m_CarportIconMap.constBegin();
	for (QMap<QString, QIcon>::const_iterator it = m_IconMap.constBegin(); it != m_IconMap.constEnd(); ++it)
	{
		if (i % 3 == 0)
		{
			pStandardItem = new QStandardItem((it1 + (i / 3)).value(), (it1 + (i / 3)).key());

			pStandardItem->setCheckable( true );
			//设置Item为三态
			pStandardItem->setTristate( true );

			//为Item设置自定义role
			pStandardItem->setData( MARK_FOLDER, ROLE_MARK_TYPE );  //标记该item为文件夹

			model->appendRow(pStandardItem);
		}
		pStandardChildItem = new QStandardItem( it.value(), it.key());
		
		//设置Item具有单选能力
		pStandardChildItem->setCheckable( true );

		//设置Item不具有三态
		pStandardChildItem->setTristate( false );

		//为Item设置自定义role
		pStandardChildItem->setData( MARK_ITEM, ROLE_MARK_TYPE ); //标记该Item为具体的项
		pStandardItem->appendRow( pStandardChildItem );
		pStandardItem->setChild( pStandardChildItem->row(),1, new QStandardItem( QString("this is %1").arg( it.key()) ));

		++i;
	}

        在鼠标左键点击TreeView中的Item时,通过对话框显示当前点击的Item的类型:是文件夹还是具体的项?

 

 

bool MyDelegate::editorEvent(QEvent * event, QAbstractItemModel * model
	, const QStyleOptionViewItem & option, const QModelIndex & index)
{
	QStandardItemModel* pModel = static_cast<QStandardItemModel*>( model );
	if (event->type() == QEvent::MouseButtonPress)
	{
		if (static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
		{
			if (model->data(index, ROLE_MARK_TYPE) == MARK_FOLDER)
			{
				QMessageBox::information(NULL, "TypeInfo", "this is folder!", QMessageBox::Ok);
			}
			else if (model->data(index, ROLE_MARK_TYPE) == MARK_ITEM )
			{
				QMessageBox::information(NULL, "TypeInfo", "this is item!", QMessageBox::Ok);
			}
		}
	}
	return QStyledItemDelegate::editorEvent( event, model, option, index );
}


<二>、系统角色的使用
        Qt定义好的角色如下:

 

 

 

例子:

 

bool MyDelegate::editorEvent(QEvent * event, QAbstractItemModel * model
	, const QStyleOptionViewItem & option, const QModelIndex & index)
{
	QStandardItemModel* pModel = static_cast<QStandardItemModel*>( model );
	if (event->type() == QEvent::MouseButtonPress)
	{
		if (static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
		{
			if (model->data(index, ROLE_MARK_TYPE) == MARK_FOLDER)
			{
				QMessageBox::information(NULL, "TypeInfo", "this is folder!", QMessageBox::Ok);
			}
			else if (model->data(index, ROLE_MARK_TYPE) == MARK_ITEM )
			{
				QMessageBox::information(NULL, "TypeInfo", "this is item!", QMessageBox::Ok);
			}

			//设置Item的图标覆盖为某一颜色
			pModel->itemFromIndex(index)->setData( QColor(0, 255, 0, 200), Qt::DecorationRole);

			//设置气泡提示信息
			pModel->itemFromIndex(index)->setData(QString("Tip:%1").arg(pModel->itemFromIndex(index)->text() ), Qt::ToolTipRole);

			//设置背景色
			pModel->itemFromIndex(index)->setData(QColor(232, 209, 57, 200), Qt::BackgroundRole);
		}
	}
	return QStyledItemDelegate::editorEvent( event, model, option, index );
}

效果:

 


 

 

参看:http://www.tuicool.com/articles/FvaYNn

参看:http://www.it165.net/pro/html/201405/14029.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值