Qt实现QListView自定义Item界面——仿QQ好友界面
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小时内删除。