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

1.可以删除列表中图标

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

3.添加分组

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

自定义的数据模型

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

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

运行结果

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

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

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

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

Qt实现QQ好友下拉列表(用QListView实现,所以还得定义它的Model)的更多相关文章

  1. Qt实现 QQ好友列表QToolBox

    简述 QToolBox类提供了一个列(选项卡式的)部件条目. QToolBox可以在一个tab列上显示另外一个,并且当前的item显示在当前的tab下面.每个tab都在tab列中有一个索引位置.tab ...

  2. 基于Qt的相似QQ好友列表抽屉效果的实现

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/shuideyidi/article/details/30619167     前段时间在忙毕业设计, ...

  3. Qt实现QQ界面

    1.Qt实现QQ界面是通过QToolBox类来实现的,基本结构是:QToolBox里面装QGroupBox,然后QGroupBox里面装QToolButton,设置好相关属性即可 2.定义类继承QTo ...

  4. js实现打开网页自动弹出添加QQ好友邀请窗口

    我们有时进一些网面或专题页面会自动弹出一个加为好友的对话框了,在研究了很久之后发现可以直接使用js来实现,下面我们一起来看js实现打开网页自动弹出添加QQ好友邀请窗口的方法. 第一步.JS脚本 这个是 ...

  5. 微信sdk分享,苹果手机分享到qq好友和qq空间没有反应

    最近线上程序苹果手机进行微信分享时,分享到qq好友和qq空间,无法调用分享程序,从微信跳转到qq后就没有反应了,但是安卓手机分享就没事? 解决:调用微信sdk分享时,分享的url(link)的参数不能 ...

  6. iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一)

    iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(一) 一.项目结构和plist文件 二.实现代码 1.说明: 主控制器直接继承UITableViewController // ...

  7. java模仿qq好友面板的布局(BoxLayout问题)

    .............. JLabel ll = new JLabel(dlg.getNameText() + ":" + dlg.getIPText(), ii[index] ...

  8. 使用Javascript无限添加QQ好友原理解析

    做QQ营销的朋友都知道,QQ加好友是有诸多限制的,IP限制,次数限制,二维码限制,人数限制,使用软件自动加好友会遇到各种各样的问题,很多软件通过模拟人工添加QQ号码,在添加几个之后就会遇到腾讯规则限制 ...

  9. [iOS基础控件 - 6.9.3] QQ好友列表Demo TableView

    A.需求 1.使用plist数据,展示类似QQ好友列表的分组.组内成员显示缩进功能 2.组名使用Header,展示箭头图标.组名.组内人数和上线人数 3.点击组名,伸展.缩回好友组   code so ...

随机推荐

  1. js超简单日历

    用原生js写了一个超级简单的日历.当做是练习js中的Date类型. 思路: 获取某个日期,根据年份计算出每个月的天数. 利用Date中的getDay()知道该月份的第一天为星期几. 循环创建表格,显示 ...

  2. Onvif协议

    ONVIF致力于通过全球性的开放界面标准来推进网络视频在安防市场的应用,这一接口界面标准将确保不同厂商生产的网络视频监控产品具有互通性.2008年11月,论坛正式发布了ONVIF第一版规范ONVIF核 ...

  3. 解决gnuplot中'Terminal type set to 'unknown'不能显示绘图的问题

    安装gnuplot: sudo apt-get install gnuplot 安装成功后,在终端输入gnuplot,进入gnuplot. 直接进行一个小测试: plot sin(x) 发现不能显示绘 ...

  4. java覆写equals方法

    何时需要重写equals() 当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念). object规范规定,如果要重写equals(),也要重写hashcode() 如何覆写equals() ...

  5. Android各种效果集合

    QQ侧滑风格:http://www.cnblogs.com/lichenwei/p/4111252.html,通过继承HorizontalScrollView类来实现的.

  6. Nginx简单操作

    Nginx简单操作 平滑重启:读取配置文件,正确后启动新nginx,关闭旧服务进程 # kill HUP nginx.pid # /usr/sbin/nginx -c /etc/nginx/nginx ...

  7. http://riddle.arthurluk.net walkthrough

    MSVFMyU4MCU4MWh0dHAlM0ElMkYlMkZyaWRkbGUuYXJ0aHVybHVrLm5ldCUyRnN0YWdlb25lLnBocCUwRCUwQTIlRTMlODAlODFo ...

  8. 升级到iis7 的web.config配置

    经典模式或集成模式都识别system.webServers节点 aspnet的isapi分32位和64位 不存在时会报404或403

  9. Nginx阅读笔记(三)之proxy_pass用法

    在nginx中配置proxy_pass时,当在后面的url加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走,如果没有/,则会把匹配的路径部分也给代理走. 假设访问 ...

  10. 高级UNIX环境编程3 FILE IO

    POSIX中,STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO 对应0,1,2 每个打开的文件都有一个与其想关联的 "current file offset& ...