Qt实现QQ好友下拉列表

    偶然发现Qt有个控件可以实现下拉列表,所以就试着实现一下类似QQ面板的下拉列表,这里主要实现几个功能:

   1.可以删除列表中图标

   2.可以像qq一样的,把某个分组下的图标转移到另外的分组

  3.添加分组

代码里写了注释了,这里就不重复了,下面直接看代码吧。

自定义的数据模型

ListModel继承了QAbstractListModel,主要是实现要显示的数据结构。用的是model/view的三层结构,这样好拆分


struct ListItemData
{
	QString  iconPath;
	QString  Name;

};

class ListModel:public QAbstractListModel
{
	Q_OBJECT
public:
	ListModel(QObject *parent = NULL);
	~ListModel();

	void init();
	void addItem(ListItemData *pItem);
	QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;
	int	rowCount ( const QModelIndex & parent = QModelIndex() ) const;
	void deleteItem(int index);
	ListItemData* getItem(int index );
protected:
private:
	vector m_ItemDataVec;
};
ListModel::ListModel( QObject *parent /*= NULL*/ ):QAbstractListModel(parent)
{
	init();
}

ListModel::~ListModel()
{

}

QVariant ListModel::data( const QModelIndex & index, int role /*= Qt::DisplayRole */ ) const
{
	if (index.row() > m_ItemDataVec.size())
	{
		return QVariant();
	} 
	else
	{
	   switch (role)
	   {
	   case Qt::DisplayRole:
		   {
			   return m_ItemDataVec[index.row()]->Name;
		   }
	   	break;
	   case Qt::DecorationRole:
		   {
			   return QIcon(m_ItemDataVec[index.row()]->iconPath);
		   }
		   break;
	 case Qt::SizeHintRole:
		   {
			   return QSize(10,50);

		   }
	   }
	}
	return QVariant();
}



int ListModel::rowCount( const QModelIndex & parent /*= QModelIndex() */ ) const
{
	return m_ItemDataVec.size();
}

void ListModel::init()
{
	for (int i = 1; i < 26; ++i)
	{ 
		ListItemData *pItem = new ListItemData;
		pItem->Name = QString::number(i);
		pItem->iconPath = QString(":/QQPanel/Resources/%1.jpg").arg(i);
		QFile Iconfile(pItem->iconPath);
		if (Iconfile.exists())
		{
			m_ItemDataVec.push_back(pItem);
		}
		
	}
}

void ListModel::deleteItem( int index )
{
	vector::iterator it = m_ItemDataVec.begin();
	m_ItemDataVec.erase(it + index);
}

void ListModel::addItem( ListItemData *pItem )
{
	if (pItem)
	{
		this->beginInsertRows(QModelIndex(),m_ItemDataVec.size(),m_ItemDataVec.size() + 1);
		m_ItemDataVec.push_back(pItem);
		this->endInsertRows();
	}
	
}

ListItemData* ListModel::getItem( int index )
{
	if (index > -1 && index < m_ItemDataVec.size())
	{
		return m_ItemDataVec[index];
	}
}




自定义的列表

这个类才是重点,因为这里实现了删除和转移图标的几个重要的函数。
class MyListView:public QListView
{
	Q_OBJECT
public:
	MyListView(QWidget *parent = NULL);
	~MyListView();
	void setListMap(map *pListMap);
	void addItem(ListItemData *pItem);
protected:
	void contextMenuEvent ( QContextMenuEvent * event );
private slots:
	void deleteItemSlot(bool bDelete);
	void moveSlot(bool bMove);
private:
	int  m_hitIndex;
	ListModel   *m_pModel;
	记录分组和分组名字的映射关系,这个值跟QQPanel类中的映射组的值保持一致 
	//这里还有一个用处就是在弹出的菜单需要分组的名称
	map *m_pListMap;   
	//记录每个菜单项对应的列表,才能知道要转移到那个分组
	map m_ActionMap;   
};


MyListView::MyListView( QWidget *parent /*= NULL*/ ):QListView(parent)
{
	m_hitIndex = -1;
	m_pModel = new ListModel;
	this->setModel(m_pModel);
	m_pListMap = NULL;
}

MyListView::~MyListView()
{

}

void MyListView::contextMenuEvent( QContextMenuEvent * event )
{
	int hitIndex = this->indexAt(event->pos()).column();
	if (hitIndex > -1)
	{
		QMenu *pMenu = new QMenu(this);
		QAction *pDeleteAct = new QAction(tr("删除"),pMenu);
		pMenu->addAction(pDeleteAct);
		connect(pDeleteAct,SIGNAL(triggered (bool)),this,SLOT(deleteItemSlot(bool)));
		QMenu *pSubMenu = NULL;
		map::iterator it = m_pListMap->begin();
		for (it;it != m_pListMap->end();++it)
		{
			if (!pSubMenu)
			{
				pSubMenu = new QMenu(tr("转移联系人至") ,pMenu);
				pMenu->addMenu(pSubMenu);
			}
			if (it->first != this)
			{
				QAction *pMoveAct = new QAction( it->second ,pMenu);
				//记录菜单与分组的映射,在moveSlot()响应时需要用到。
				m_ActionMap.insert(pair(pMoveAct,it->first));
				pSubMenu->addAction(pMoveAct);
				connect(pMoveAct,SIGNAL(triggered (bool)),this,SLOT(moveSlot(bool)));
			}
			
		}

		pMenu->popup(mapToGlobal(event->pos()));
	}
}

void MyListView::deleteItemSlot( bool bDelete )
{
	int index = this->currentIndex().row();
	if (index > -1)
	{
		m_pModel->deleteItem(index);
	}
}

void MyListView::setListMap( map *pListMap )
{
	m_pListMap = pListMap;
}

void MyListView::addItem( ListItemData *pItem )
{
	m_pModel->addItem(pItem);
}

void MyListView::moveSlot( bool bMove )
{
	QAction *pSender = qobject_cast(sender());
	if (pSender)
	{
		//根据点击的菜单,找到相应的列表,然后才能把图标转移过去
		MyListView *pList = m_ActionMap.find(pSender)->second;
		if (pList)
		{
			int index = this->currentIndex().row();
			ListItemData *pItem = m_pModel->getItem(index);
			pList->addItem(pItem);
			//添加到别的分组,就在原来的分组中删除掉了
			m_pModel->deleteItem(index);
		}
	}
	//操作完了要把这个临时的映射清空
	m_ActionMap.clear();
}

自定义的主控件

class QQPanel : public QWidget
{
	Q_OBJECT
	
public:
	QQPanel(QWidget *parent = 0, Qt::WFlags flags = 0);
	~QQPanel();

protected:
	void contextMenuEvent ( QContextMenuEvent * event );

protected slots:
	void addGroupSlot(bool addgroup);
private:
	QToolBox    *m_pBox;
	map *m_pListMap;    //记录分组和分组名字的映射关系,好在转移图标时知道转移到那个分组

};

QQPanel::QQPanel(QWidget *parent, Qt::WFlags flags)
	: QWidget(parent, flags)
{
	m_pBox = new QToolBox(this);
	m_pListMap = new map();
	MyListView *pListView = new MyListView(this);
	pListView->setViewMode(QListView::ListMode);
	pListView->setStyleSheet("QListView{icon-size:40px}");
	m_pBox->addItem(pListView,tr("我的好友"));
	m_pListMap->insert(pair(pListView,tr("我的好友")));

	MyListView *pListView1 = new MyListView(this);
	pListView1->setViewMode(QListView::ListMode);
	pListView1->setStyleSheet("QListView{icon-size:40px}");
	m_pBox->addItem(pListView1,tr("陌生人"));
	m_pListMap->insert(pair(pListView1,tr("陌生人")));

	pListView->setListMap(m_pListMap);
	pListView1->setListMap(m_pListMap);
	m_pBox->setFixedWidth(150);
	m_pBox->setMinimumHeight(500);
	this->setMinimumSize(200,500);
	//ui.setupUi(this);
}

QQPanel::~QQPanel()
{

}

void QQPanel::contextMenuEvent( QContextMenuEvent * event )
{
	QMenu *pMenu = new QMenu(this);
	QAction *pAddGroupAct = new QAction(tr("添加分组"),pMenu);
	pMenu->addAction(pAddGroupAct);
	connect(pAddGroupAct,SIGNAL(triggered (bool)),this,SLOT(addGroupSlot(bool)));
	pMenu->popup(mapToGlobal(event->pos()));
}


void QQPanel::addGroupSlot( bool addgroup )
{
    QString name = QInputDialog::getText(this,tr("输入分组名"),tr(""));
	if (!name.isEmpty())
	{
		MyListView *pListView1 = new MyListView(this);
		pListView1->setViewMode(QListView::ListMode);
		pListView1->setStyleSheet("QListView{icon-size:40px}");
		m_pBox->addItem(pListView1,name);
		m_pListMap->insert(pair(pListView1,name));
	}
	//要确保每个MyListView钟的m_pListMap都是一致的,不然就会有错了。
	//因为弹出的菜单进行转移的时候需要用到
	map::iterator it = m_pListMap->begin();
	for (it; it != m_pListMap->end(); ++it)
	{
		MyListView* pList = it->first;
		pList->setListMap(m_pListMap);
	}
}

运行结果

Qt实现QQ好友下拉列表_第1张图片 Qt实现QQ好友下拉列表_第2张图片

由以上两个截图显示,我的好友和陌生人的个有5个图标


Qt实现QQ好友下拉列表_第3张图片 Qt实现QQ好友下拉列表_第4张图片

以上两个截图显示,把陌生人中图标5转移到我的好友里

Qt实现QQ好友下拉列表_第5张图片 Qt实现QQ好友下拉列表_第6张图片

以上两个截图,显示添加了一个分组,黑名单,因为我默认列表在创建时都有相同的5个图标

Qt实现QQ好友下拉列表_第7张图片 Qt实现QQ好友下拉列表_第8张图片 Qt实现QQ好友下拉列表_第9张图片

  以上三个截图显示了把黑名单里的图标5转移到了我的好友分组里了

当然这个程序算是比较简单的。还不能真正的跟QQ的面板相比,还不能把所有的分组都收起来。以后再慢慢研究怎么实现了,



你可能感兴趣的:(Qt学习笔记,Qt)