Qt 实现QListView ⾃定义Item 界⾯——仿QQ 好友界⾯ ⼀直都认为,⽤最通俗的语⾔,讲解最深刻的技术,是每⼀个技术交流者应该考虑的事情,今天朋友问我,好友列表该怎么实现。我想起之前上⽹查阅的时候,发现⽹上介绍这块的内容甚少,⽽且讲解的不够好,于是,本着互相交流的精神,在这⾥讲解⼀下我是怎么实现QQ 好友列表的。
1、Q :关于好友列表到底是QTreeWidget/QTreeView 还是QListWidget/QListView 的问题?
A :相信⼤家初次⼀看,⼤部分都认为是QTreeWidget ,其实是⽤QListWidget 或者QListView 均可简单实现,在数据多的时候,QListWidget 性能会降低,不过,对于好友列表来说,QListWidget ⾜以,并且更加简单。所以,我继承的是QListWidget 来实现。
2、Q :关于如何实现⼀个Item 具有多种信息,包括头像、⽤户名、个性签名等?
A :该Item 其实是⼀个继承了QWidget 的⾃定义buddy 类,把你所想要的信息全部在该buddy 类⾥⾯布局好,甚⾄可以加进按钮,⾃定义的好处就在于,你想到什么,就能⼲什么,然后在QListWiget ⾥⾯⾥通过实现
即可。3、Q :关于如何实现好友的展开与隐藏?
A :这部分⾥我设置了两个容器:
其中,groupMap ⽤来存放key 为项,value 为组的数据,⽐如我增加了⼀个“我的好友”的组,则存进去是key :我的好友,value :我的好友;接着,在isHideMap 存放key :我的好友,value :false ,表⽰默认该组是未展开的;紧接着,如果在“我的好友”⾥,我增加了⼀个好友“逍遥圣帝”,则存进去的是:key :逍遥圣帝,value :我的好友,这样处理的关键是为了保存好组与好友的关系;最后再利⽤isHideMap 来判断组的状态,如果是隐藏,则通过遍历groupMap ⾥⾯的好友,使之显⽰,否则,反之。
4、Q :关于如何实现美化效果?
A :直接⽤QSS 就可以了。
下⾯直接贴出源代码,我已经在源代码⾥⾯详细给每⼀个关键步骤进⾏了说明,所以就不进⾏阐述了,相信⼤家看得懂的,如有不懂可以追加评论,第⼀时间回复你们,下⾯是实现⼀个QQ 好友列表的简单功能,对于其他功能⼤家好好拓展即可~~
⼀、⾸先是实现具有各种信息的Buddy 类:
personListBuddy.h
personListBuddy.cpp [cpp]
01. QListWidgetItem *newItem = new QListWidgetItem(); //创建⼀个newItem 02. this ->insertItem(row(currentItem)+unt(),newItem); //将该newItem 插⼊到后⾯ 03.
this ->setItemWidget(newItem, buddy); //将buddy 赋给该newItem [cpp]
01. QMap<QListWidgetItem*,QListWidgetItem*> groupMap; // 组容器 - key:项 value:组 02. QMap<QListWidgetItem*,bool > isHideMap;//⽤来判断该组是否隐藏了 [cpp]
01. #ifndef PERSONLISTBUDDY_H 02. #define PERSONLISTBUDDY_H 03. #include <QWidget> 04. #include <QLabel> 05. #include <QEvent> 06. //⾃定义信息Item 类 07. class personListBuddy : public QWidget 08. { 09. Q_OBJECT 10. public : 11. explicit personListBuddy(QWidget *parent = 0); 12. void initUi();//初始化Ui 13. QWidget *head; //头像 14. QLabel *name; //⽤户名 15. QLabel *sign; //个性签名 16. QString headPath;//头像路径 17. bool eventFilter(QObject *obj, QEvent *event);//事件过滤器 18. 19. signals: 20. 21. public slots: 22. 23. }; 24. #endif // PERSONLISTBUDDY_H
⼆、实现好友列表personList 类:personList.h [cpp]
01. #include "personlistbuddy.h" 02. #include <QPainter> 03. personListBuddy::personListBuddy(QWi
dget *parent) : 04. QWidget(parent) 05. { 06. initUi(); 07. } 08. //初始化Ui 09. void personListBuddy::initUi() 10. { 11. //初始化 12. head=new QWidget(this ); 13. name=new QLabel(this ); 14. sign=new QLabel(this ); 15. //设置头像⼤⼩ 16. head->setFixedSize(40,40); 17. //设置个性签名字体为灰⾊ 18. QPalette color; 19. color.setColor(QPalette::Text,Qt::gray); 20. sign->setPalette(color); 21. //布局 22. head->move(7,7); 23. name->move(54,10); 24. sign->move(54,27); 25. //装载事件过滤器 26. head->installEventFilter(this ); 27. } 28. //事件过滤器,主要是为了让图⽚能够全部填充在head ⾥⾯ 29. bool personListBuddy::eventFilter(QObject *obj, QEvent *event) 30. { 31. if (obj == head) 32. { 33. if (event->type() == QEvent::Paint) 34. { 35. QPainter painter(head); 36. painter.drawPixmap(head->rect(), QPixmap(headPath)); 37. } 38. } 39. return QWidget::eventFilter(obj, event); 40. } [cpp]
01. #ifndef PERSONLIST_H 02. #define PERSONLIST_H 03. #include <QListWidget> 04. #include <QMenu> 05. #include <QMouseEvent> 06. #include <QLineEdit> 07. //⾃定义QListWidget 08. class personList : public QListWidget //继承QListWidget ,可以使⽤它本⾝⾃带的函数,更⽅便 09. { 10. Q_OBJECT 11. public : 12. explicit personList(QListWidget *parent = 0); 13. void mousePressEvent(QMouseEvent *event);//⿏标点击事件 14. void contextMenuEvent(QContextMenuEvent*);//菜单事件,为了显⽰菜单 15. void initMenu();//初始化菜
单 16. QMenu *blankMenu;//点击空⽩上的菜单 17. QMenu *groupMenu;//点击组上的菜单 18. QMenu *personMenu;//点击⼈上的菜单 19. QMap<QListWidgetItem*,QListWidgetItem*> groupMap; // 组容器 - key:项 value:组 20. QMap<QListWidgetItem*,bool > isHideMap;//⽤来判断该组是否隐藏了 21. QLineEdit *groupNameEdit;//组的名字,重命名的时候需要⽤到 22. QListWidgetItem *currentItem;//当前的项 23. 24. signals: 25. 26. public slots: 27. void slotAddGroup(); //添加组 28. void slotDelGroup(); //删除组
personList.cpp 29. void slotAddBuddy(); //添加好友 30. void slotDelBuddy(); //删除好友 31. void slotRename(); //重命名组 32. void slotRenameEditFshed();//命名完成 33. 34. }; 35. #endif // PERSONLIST_H [cpp]
01. #include "personlist.h" 02. #include <QAction> 03. #include <QIcon> 04. #include "personlistbuddy.h" 05. personList::personList(QListWidget *parent) : 06. QListWidget(parent) 07. { 08. setFocusPolicy(Qt::NoFocus); // 去除item 选中时的虚线边框 09. setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//⽔平滚动条关闭 10. initMenu(); 11. } 12. //初始化菜单 13. void personList::initMenu() 14. { 15. //初始化: 16. blankMenu = new QMenu(); 17. groupMenu = new QMenu(); 18. personMenu = new QMenu(); 19. groupNameEdit=new QLineEdit(); 20. QAction *addGroup = new QAction("添加分组", this ); 21. QAction *delGroup = n
ew QAction("删除该组", this ); 22. QAction *rename = new QAction("重命名", this ); 23. QAction *addBuddy = new QAction("添加好友",this ); 24. QAction *delBuddy = new QAction("删除好友", this ); 25. //设置: 26. groupNameEdit->setParent(this ); //设置⽗类 27. groupNameEdit->hide(); //设置初始时隐藏 28. groupNameEdit->setPlaceholderText("未命名");//设置初始时的内容 29. //布局: 30. blankMenu->addAction(addGroup); 31. groupMenu->addAction(delGroup); 32. groupMenu->addAction(rename); 33. groupMenu->addAction(addBuddy); 34. personMenu->addAction(delBuddy); 35. //信息槽: 36. connect(groupNameEdit,SIGNAL(editingFinished()),this ,SLOT(slotRenameEditFshed())); 37. connect(addGroup,SIGNAL(triggered()),this ,SLOT(slotAddGroup())); 38. connect(delGroup,SIGNAL(triggered()),this ,SLOT(slotDelGroup())); 39. connect(rename,SIGNAL(triggered()),this ,SLOT(slotRename())); 40. connect(addBuddy,SIGNAL(triggered()),this ,SLOT(slotAddBuddy())); 41. connect(delBuddy,SIGNAL(triggered()),this ,SLOT(slotDelBuddy())); 42. } 43. //⿏标点击事件 44. void personList::mousePressEvent(QMouseEvent *event) 45. { 46.
QListWidget::mousePressEvent(event); // 如果不调⽤基类mousePressEvent ,item 被select 会半天不响应,调⽤⽗类,让QSS 起效,因为QSS 基于⽗类QListWidget ,⼦类就是⼦窗⼝,就是最上层窗⼝,是覆盖在⽗窗⼝上的,所以先于⽗窗⼝捕获消息 47. //防⽌⼀种特殊情况:给新item 命名、点击
其他item 或空⽩处时,指向新item 的currentItem 被赋予其他item 48. if (groupNameEdit->isVisible() && !(groupNameEdit->rect().contains(event->pos()))) 49. { 50. if (groupNameEdit->text()!=NULL) 51. currentItem->setText(groupNameEdit->text()); 52. groupNameEdit->setText(""); 53. groupNameEdit->hide(); 54. } 55. currentItem = this ->itemAt(mapFromGlobal(QCursor::pos()));//⿏标位置的Item ,不管右键左键都获取 56.
if (event->button()==Qt::LeftButton && currentItem!=NULL && currentItem==groupMap.value(currentItem))//如果点击的左键并且是点击的是组 57. { 58. if (isHideMap.value(currentItem)) //如果先前是隐藏,则显⽰ 59. { 60. foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))//遍历组的对应的项(包括⾃⾝和好友) 61. if (subItem!=currentItem) //如果是组的话不进⾏处理 62. {
63. subItem->setHidden(false); //好友全部显⽰
64. }
65. isHideMap.insert(currentItem,false); //设置该组为显⽰状态
66. currentItem->setIcon(QIcon(":/arrowDown"));
67. }
68. else//否则,先前是显⽰,则隐藏
69. {
70. foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))//遍历组的对应的项(包括⾃⾝和好友)
71. if(subItem!=currentItem) //如果是组的话不进⾏处理
72. {
73. subItem->setHidden(true); //好友全部隐藏
74. }
75. isHideMap.insert(currentItem,true); //设置该组为隐藏状态
76. currentItem->setIcon(QIcon(":/arrowRight"));
77. }
78. }
79. }
80. //菜单事件,为了显⽰菜单,点击⿏标右键响应,⿏标点击事件mousePressEvent优先于contextMenuEvent
81. void personList::contextMenuEvent(QContextMenuEvent *event)
82. {
83. QListWidget::contextMenuEvent(event); //调⽤基类事件
qq分组简单84. if(currentItem==NULL) //如果点击到的是空⽩处
85. {
86. blankMenu->exec(QCursor::pos());
87. return;
88. }
89. if(currentItem==groupMap.value(currentItem)) // 如果点击到的是组
90. groupMenu->exec(QCursor::pos());
91. else//否则点击到的是好友
92. personMenu->exec(QCursor::pos());
93. }
94. //添加组
95. void personList::slotAddGroup()
96. {
97. QListWidgetItem *newItem=new QListWidgetItem(QIcon(":/arrowRight"),"未命名"); //创建⼀个Item
98. newItem->setSizeHint(QSize(this->width(),25));//设置宽度、⾼度
99. this->addItem(newItem); //加到QListWidget中
100. groupMap.insert(newItem,newItem);//加到容器groupMap⾥,key和value都为组
101. isHideMap.insert(newItem,true); //设置该组隐藏状态
102. groupNameEdit->raise();
103. groupNameEdit->setText(tr("未命名")); //设置默认内容
104. groupNameEdit->selectAll(); //设置全选
105. groupNameEdit->setGeometry(this->visualItemRect(newItem).left()+15,this->visualItemRect(newItem).top()+1,this->visualItemRect(newItem).width(),this->visualItemRect(newItem).height()-2);//出现的位置
106. groupNameEdit->show(); //显⽰
107. groupNameEdit->setFocus(); //获取焦点
108. currentItem = newItem; // 因为要给group命名,所以当前的currentItem设为该group
109. }
110. //删除组
111. void personList::slotDelGroup()
112. {
113. foreach(QListWidgetItem* item, groupMap.keys(currentItem)) //遍历该组的所有好友和⾃⾝的组
114. {
115. ve(item); //移除
116. delete item; //删除
117. }
118. ve(currentItem); //移除
119. }
120. //重命名
121. void personList::slotRename()
122. {
123. groupNameEdit->raise();
124. groupNameEdit->setGeometry(this->visualItemRect(currentItem).left()+15,this-
>visualItemRect(currentItem).top()+1,this->visualItemRect(currentItem).width(),this->visualItemRect(currentItem).height()-
2);//出现的位置
125. groupNameEdit->setText(currentItem->text()); //获取该组名内容
126. groupNameEdit->show(); //显⽰
127. groupNameEdit->selectAll(); //全选
128. groupNameEdit->setFocus(); //获取焦点
129. }
130. //添加好友,主要是为了测试功能,实际⼯程⾥可以改成动态读取数据库进⾏添加好友
131. void personList::slotAddBuddy()
132. {
133. personListBuddy *buddy=new personListBuddy(); //创建⼀个⾃⼰定义的信息类
134. buddy->headPath=":/head"; //设置头像路径
135. buddy->name->setText("逍遥圣帝"); //设置⽤户名
136. buddy->sign->setText("⽤通俗的语⾔,讲深刻的技术。"); //设置个性签名
137. QList<QListWidgetItem*> tem = groupMap.keys(currentItem);//当前组对应的项(包括组本⾝和好友)复制给tem 138. //关键代码
三、美化⽤到的QSS :139. QListWidgetItem *newItem = new QListWidgetItem(); //创建⼀个newItem 140. this ->insertItem(row(currentItem)+unt(),newItem); //将该newItem 插⼊到后⾯ 141. this ->setItemWidget(newItem, buddy); //将buddy 赋给该newItem 142. groupMap.insert(newIt
em,currentItem); //加进容器,key 为好友,value 为组 143. if (isHideMap.value(currentItem)) //如果该组是隐藏,则加进去的好友设置为隐藏 144. newItem->setHidden(true ); 145. else //否则,该好友设置为显⽰ 146. newItem->setHidden(false ); 147. } 148. //删除好友 149. void personList::slotDelBuddy() 150. { 151. ve(currentItem); //移除该好友 152. delete currentItem; //删除 153. } 154. //重命名完成 155. void personList::slotRenameEditFshed() 156. { 157. if (groupNameEdit->text()!=NULL) //如果重命名编辑框不为空 158. currentItem->setText(groupNameEdit->text()); //更新组名 159. groupNameEdit->setText(""); 160. groupNameEdit->hide(); //隐藏重命名编辑框 161. }
[cpp]
01. QListWidget{ 02. background:white; 03. color:black; 04. border:none; 05. } 06. 07. QListWidget::item{ 08. border:none; 09. height: 54px; 10. } 11. 12. QListWidget::item:hover{ 13. background:rgb(252,240,193) 14. } 15. 16. QListWidget::item:selected{ 17. background:rgb(252,233,161); 18. color:black; 19. } 20. 21. QScrollBar:vertical { 22. background:transparent; 23. width:9px; 24. margin: 0px 0px 2px 0px; 25. } 26. 27. QScrollBar::handle:vertical { 28. background: rgb(195, 195, 195); 29. min-height: 20px; 30. border-radius: 3px; 31. } 32. 33. QScrollBar::handle:vertical:hover{ 34. background:rgba(0,0,0,30
%); 35. } 36. 37. QScrollBar::add-line:vertical { 38. height: 0px; 39. subcontrol-position: bottom; 40. subcontrol-origin: margin; 41. } 42. 43. QScrollBar::sub-line:vertical { 44. height: 0px; 45. subcontrol-position: top; 46. subcontrol-origin: margin; 47. }
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论