Qt实现QQ好友下拉列表

来源:互联网 发布:淘宝卖家接收信息软件 编辑:程序博客网 时间:2024/06/04 08:49

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

   1.可以删除列表中图标

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

  3.添加分组

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

自定义的数据模型

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

struct ListItemData{QString  iconPath;QString  Name;};class ListModel:public QAbstractListModel{Q_OBJECTpublic:ListModel(QObject *parent = NULL);~ListModel();void init();void addItem(ListItemData *pItem);QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;introwCount ( const QModelIndex & parent = QModelIndex() ) const;void deleteItem(int index);ListItemData* getItem(int index );protected:private:vector<ListItemData*> 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<ListItemData*>::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_OBJECTpublic:MyListView(QWidget *parent = NULL);~MyListView();void setListMap(map<MyListView*,QString> *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<MyListView*,QString> *m_pListMap;   //记录每个菜单项对应的列表,才能知道要转移到那个分组map<QAction*,MyListView*> 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<MyListView*,QString>::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<QAction*,MyListView*>(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<MyListView*,QString> *pListMap ){m_pListMap = pListMap;}void MyListView::addItem( ListItemData *pItem ){m_pModel->addItem(pItem);}void MyListView::moveSlot( bool bMove ){QAction *pSender = qobject_cast<QAction*>(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_OBJECTpublic: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<MyListView*,QString> *m_pListMap;    //记录分组和分组名字的映射关系,好在转移图标时知道转移到那个分组};

QQPanel::QQPanel(QWidget *parent, Qt::WFlags flags): QWidget(parent, flags){m_pBox = new QToolBox(this);m_pListMap = new map<MyListView*,QString>();MyListView *pListView = new MyListView(this);pListView->setViewMode(QListView::ListMode);pListView->setStyleSheet("QListView{icon-size:40px}");m_pBox->addItem(pListView,tr("我的好友"));m_pListMap->insert(pair<MyListView*,QString>(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<MyListView*,QString>(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<MyListView*,QString>(pListView1,name));}//要确保每个MyListView钟的m_pListMap都是一致的,不然就会有错了。//因为弹出的菜单进行转移的时候需要用到map<MyListView*,QString>::iterator it = m_pListMap->begin();for (it; it != m_pListMap->end(); ++it){MyListView* pList = it->first;pList->setListMap(m_pListMap);}}

运行结果



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




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



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



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

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



原创粉丝点击