zoukankan      html  css  js  c++  java
  • Qt实现QQ好友下拉列表(用QListView实现,所以还得定义它的Model)

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

       1.可以删除列表中图标

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

      3.添加分组

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

    自定义的数据模型

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

    [cpp] view plain copy
     
    1. struct ListItemData  
    2. {  
    3.     QString  iconPath;  
    4.     QString  Name;  
    5.   
    6. };  
    7.   
    8. class ListModel:public QAbstractListModel  
    9. {  
    10.     Q_OBJECT  
    11. public:  
    12.     ListModel(QObject *parent = NULL);  
    13.     ~ListModel();  
    14.   
    15.     void init();  
    16.     void addItem(ListItemData *pItem);  
    17.     QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const ;  
    18.     int rowCount ( const QModelIndex & parent = QModelIndex() ) const;  
    19.     void deleteItem(int index);  
    20.     ListItemData* getItem(int index );  
    21. protected:  
    22. private:  
    23.     vector<ListItemData*> m_ItemDataVec;  
    24. };  
    [cpp] view plain copy
     
    1. <pre name="code" class="cpp">ListModel::ListModel( QObject *parent /*= NULL*/ ):QAbstractListModel(parent)  
    2. {  
    3.     init();  
    4. }  
    5.   
    6. ListModel::~ListModel()  
    7. {  
    8.   
    9. }  
    10.   
    11. QVariant ListModel::data( const QModelIndex & index, int role /*= Qt::DisplayRole */ ) const  
    12. {  
    13.     if (index.row() > m_ItemDataVec.size())  
    14.     {  
    15.         return QVariant();  
    16.     }   
    17.     else  
    18.     {  
    19.        switch (role)  
    20.        {  
    21.        case Qt::DisplayRole:  
    22.            {  
    23.                return m_ItemDataVec[index.row()]->Name;  
    24.            }  
    25.         break;  
    26.        case Qt::DecorationRole:  
    27.            {  
    28.                return QIcon(m_ItemDataVec[index.row()]->iconPath);  
    29.            }  
    30.            break;  
    31.      case Qt::SizeHintRole:  
    32.            {  
    33.                return QSize(10,50);  
    34.   
    35.            }  
    36.        }  
    37.     }  
    38.     return QVariant();  
    39. }  
    40.   
    41.   
    42.   
    43. int ListModel::rowCount( const QModelIndex & parent /*= QModelIndex() */ ) const  
    44. {  
    45.     return m_ItemDataVec.size();  
    46. }  
    47.   
    48. void ListModel::init()  
    49. {  
    50.     for (int i = 1; i < 26; ++i)  
    51.     {   
    52.         ListItemData *pItem = new ListItemData;  
    53.         pItem->Name = QString::number(i);  
    54.         pItem->iconPath = QString(":/QQPanel/Resources/%1.jpg").arg(i);  
    55.         QFile Iconfile(pItem->iconPath);  
    56.         if (Iconfile.exists())  
    57.         {  
    58.             m_ItemDataVec.push_back(pItem);  
    59.         }  
    60.           
    61.     }  
    62. }  
    63.   
    64. void ListModel::deleteItem( int index )  
    65. {  
    66.     vector<ListItemData*>::iterator it = m_ItemDataVec.begin();  
    67.     m_ItemDataVec.erase(it + index);  
    68. }  
    69.   
    70. void ListModel::addItem( ListItemData *pItem )  
    71. {  
    72.     if (pItem)  
    73.     {  
    74.         this->beginInsertRows(QModelIndex(),m_ItemDataVec.size(),m_ItemDataVec.size() + 1);  
    75. <span style="white-space:pre">      </span>m_ItemDataVec.push_back(pItem);  
    76. <span style="white-space:pre">      </span>this->endInsertRows();  
    77.     }  
    78.       
    79. }  
    80.   
    81. ListItemData* ListModel::getItem( int index )  
    82. {  
    83.     if (index > -1 && index < m_ItemDataVec.size())  
    84.     {  
    85.         return m_ItemDataVec[index];  
    86.     }  
    87. }  
    88. </pre><br>  
    89. <br>  
    90. <pre></pre>  
    91. <h1><a name="t1"></a><br>  
    92. </h1>  
    93. <h1><a name="t2"></a>自定义的列表</h1>  
    94. <div>这个类才是重点,因为这里实现了删除和转移图标的几个重要的函数。</div>  
    95. <pre name="code" class="cpp">class MyListView:public QListView  
    96. {  
    97.     Q_OBJECT  
    98. public:  
    99.     MyListView(QWidget *parent = NULL);  
    100.     ~MyListView();  
    101.     void setListMap(map<MyListView*,QString> *pListMap);  
    102.     void addItem(ListItemData *pItem);  
    103. protected:  
    104.     void contextMenuEvent ( QContextMenuEvent * event );  
    105. private slots:  
    106.     void deleteItemSlot(bool bDelete);  
    107.     void moveSlot(bool bMove);  
    108. private:  
    109.     int  m_hitIndex;  
    110.     ListModel   *m_pModel;  
    111.     ////记录分组和分组名字的映射关系,这个值跟QQPanel类中的映射组的值保持一致   
    112.     //这里还有一个用处就是在弹出的菜单需要分组的名称  
    113.     map<MyListView*,QString> *m_pListMap;     
    114.     //记录每个菜单项对应的列表,才能知道要转移到那个分组  
    115.     map<QAction*,MyListView*> m_ActionMap;     
    116. };</pre><br>  
    117. <pre name="code" class="cpp">MyListView::MyListView( QWidget *parent /*= NULL*/ ):QListView(parent)  
    118. {  
    119.     m_hitIndex = -1;  
    120.     m_pModel = new ListModel;  
    121.     this->setModel(m_pModel);  
    122.     m_pListMap = NULL;  
    123. }  
    124.   
    125. MyListView::~MyListView()  
    126. {  
    127.   
    128. }  
    129.   
    130. void MyListView::contextMenuEvent( QContextMenuEvent * event )  
    131. {  
    132.     int hitIndex = this->indexAt(event->pos()).column();  
    133.     if (hitIndex > -1)  
    134.     {  
    135.         QMenu *pMenu = new QMenu(this);  
    136.         QAction *pDeleteAct = new QAction(tr("删除"),pMenu);  
    137.         pMenu->addAction(pDeleteAct);  
    138.         connect(pDeleteAct,SIGNAL(triggered (bool)),this,SLOT(deleteItemSlot(bool)));  
    139.         QMenu *pSubMenu = NULL;  
    140.         map<MyListView*,QString>::iterator it = m_pListMap->begin();  
    141.         for (it;it != m_pListMap->end();++it)  
    142.         {  
    143.             if (!pSubMenu)  
    144.             {  
    145.                 pSubMenu = new QMenu(tr("转移联系人至") ,pMenu);  
    146.                 pMenu->addMenu(pSubMenu);  
    147.             }  
    148.             if (it->first != this)  
    149.             {  
    150.                 QAction *pMoveAct = new QAction( it->second ,pMenu);  
    151.                 //记录菜单与分组的映射,在moveSlot()响应时需要用到。  
    152.                 m_ActionMap.insert(pair<QAction*,MyListView*>(pMoveAct,it->first));  
    153.                 pSubMenu->addAction(pMoveAct);  
    154.                 connect(pMoveAct,SIGNAL(triggered (bool)),this,SLOT(moveSlot(bool)));  
    155.             }  
    156.               
    157.         }  
    158.   
    159.         pMenu->popup(mapToGlobal(event->pos()));  
    160.     }  
    161. }  
    162.   
    163. void MyListView::deleteItemSlot( bool bDelete )  
    164. {  
    165.     int index = this->currentIndex().row();  
    166.     if (index > -1)  
    167.     {  
    168.         m_pModel->deleteItem(index);  
    169.     }  
    170. }  
    171.   
    172. void MyListView::setListMap( map<MyListView*,QString> *pListMap )  
    173. {  
    174.     m_pListMap = pListMap;  
    175. }  
    176.   
    177. void MyListView::addItem( ListItemData *pItem )  
    178. {  
    179.     m_pModel->addItem(pItem);  
    180. }  
    181.   
    182. void MyListView::moveSlot( bool bMove )  
    183. {  
    184.     QAction *pSender = qobject_cast<QAction*>(sender());  
    185.     if (pSender)  
    186.     {  
    187.         //根据点击的菜单,找到相应的列表,然后才能把图标转移过去  
    188.         MyListView *pList = m_ActionMap.find(pSender)->second;  
    189.         if (pList)  
    190.         {  
    191.             int index = this->currentIndex().row();  
    192.             ListItemData *pItem = m_pModel->getItem(index);  
    193.             pList->addItem(pItem);  
    194.             //添加到别的分组,就在原来的分组中删除掉了  
    195.             m_pModel->deleteItem(index);  
    196.         }  
    197.     }  
    198.     //操作完了要把这个临时的映射清空  
    199.     m_ActionMap.clear();  
    200. }  
    201. </pre><br>  
    202. <h1><a name="t3"></a>自定义的主控件</h1>  
    [cpp] view plain copy
     
    1. class QQPanel : public QWidget  
    2. {  
    3.     Q_OBJECT  
    4.       
    5. public:  
    6.     QQPanel(QWidget *parent = 0, Qt::WFlags flags = 0);  
    7.     ~QQPanel();  
    8.   
    9. protected:  
    10.     void contextMenuEvent ( QContextMenuEvent * event );  
    11.   
    12. protected slots:  
    13.     void addGroupSlot(bool addgroup);  
    14. private:  
    15.     QToolBox    *m_pBox;  
    16.     map<MyListView*,QString> *m_pListMap;    //记录分组和分组名字的映射关系,好在转移图标时知道转移到那个分组  
    17.   
    18. };  

    [cpp] view plain copy
     
    1. QQPanel::QQPanel(QWidget *parent, Qt::WFlags flags)  
    2.     : QWidget(parent, flags)  
    3. {  
    4.     m_pBox = new QToolBox(this);  
    5.     m_pListMap = new map<MyListView*,QString>();  
    6.     MyListView *pListView = new MyListView(this);  
    7.     pListView->setViewMode(QListView::ListMode);  
    8.     pListView->setStyleSheet("QListView{icon-size:40px}");  
    9.     m_pBox->addItem(pListView,tr("我的好友"));  
    10.     m_pListMap->insert(pair<MyListView*,QString>(pListView,tr("我的好友")));  
    11.   
    12.     MyListView *pListView1 = new MyListView(this);  
    13.     pListView1->setViewMode(QListView::ListMode);  
    14.     pListView1->setStyleSheet("QListView{icon-size:40px}");  
    15.     m_pBox->addItem(pListView1,tr("陌生人"));  
    16.     m_pListMap->insert(pair<MyListView*,QString>(pListView1,tr("陌生人")));  
    17.   
    18.     pListView->setListMap(m_pListMap);  
    19.     pListView1->setListMap(m_pListMap);  
    20.     m_pBox->setFixedWidth(150);  
    21.     m_pBox->setMinimumHeight(500);  
    22.     this->setMinimumSize(200,500);  
    23.     //ui.setupUi(this);  
    24. }  
    25.   
    26. QQPanel::~QQPanel()  
    27. {  
    28.   
    29. }  
    30.   
    31. void QQPanel::contextMenuEvent( QContextMenuEvent * event )  
    32. {  
    33.     QMenu *pMenu = new QMenu(this);  
    34.     QAction *pAddGroupAct = new QAction(tr("添加分组"),pMenu);  
    35.     pMenu->addAction(pAddGroupAct);  
    36.     connect(pAddGroupAct,SIGNAL(triggered (bool)),this,SLOT(addGroupSlot(bool)));  
    37.     pMenu->popup(mapToGlobal(event->pos()));  
    38. }  
    39.   
    40.   
    41. void QQPanel::addGroupSlot( bool addgroup )  
    42. {  
    43.     QString name = QInputDialog::getText(this,tr("输入分组名"),tr(""));  
    44.     if (!name.isEmpty())  
    45.     {  
    46.         MyListView *pListView1 = new MyListView(this);  
    47.         pListView1->setViewMode(QListView::ListMode);  
    48.         pListView1->setStyleSheet("QListView{icon-size:40px}");  
    49.         m_pBox->addItem(pListView1,name);  
    50.         m_pListMap->insert(pair<MyListView*,QString>(pListView1,name));  
    51.     }  
    52.     //要确保每个MyListView钟的m_pListMap都是一致的,不然就会有错了。  
    53.     //因为弹出的菜单进行转移的时候需要用到  
    54.     map<MyListView*,QString>::iterator it = m_pListMap->begin();  
    55.     for (it; it != m_pListMap->end(); ++it)  
    56.     {  
    57.         MyListView* pList = it->first;  
    58.         pList->setListMap(m_pListMap);  
    59.     }  
    60. }  

    运行结果

     
    由以上两个截图显示,我的好友和陌生人的个有5个图标
     
     
     
    以上两个截图显示,把陌生人中图标5转移到我的好友里
     
     
    以上两个截图,显示添加了一个分组,黑名单,因为我默认列表在创建时都有相同的5个图标
     
     

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

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

    http://blog.csdn.net/hai200501019/article/details/10283553

  • 相关阅读:
    Codeforces Round #274 (Div. 2)
    codeforces 477C
    ZOJ 3822 Domination
    Codeforces Round #271 (Div. 2)
    进程
    线程
    udp和tcp特点 实现文件上传
    面向对象补1
    socket基本语法和粘包
    网络编程
  • 原文地址:https://www.cnblogs.com/findumars/p/5176054.html
Copyright © 2011-2022 走看看