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里面里通过实现
- QListWidgetItem *newItem = new QListWidgetItem(); //创建一个newItem
- this->insertItem(row(currentItem)+tem.count(),newItem); //将该newItem插入到后面
- this->setItemWidget(newItem, buddy); //将buddy赋给该newItem
即可。
3、Q:关于如何实现好友的展开与隐藏?
A:这部分里我设置了两个容器:
- QMap<QListWidgetItem*,QListWidgetItem*> groupMap; // 组容器 - key:项 value:组
- QMap<QListWidgetItem*,bool> isHideMap;//用来判断该组是否隐藏了
其中,groupMap用来存放key为项,value为组的数据,比如我增加了一个“我的好友”的组,则存进去是key:我的好友,value:我的好友;接着,在isHideMap存放key:我的好友,value:false,表示默认该组是未展开的;紧接着,如果在“我的好友”里,我增加了一个好友“逍遥圣帝”,则存进去的是:key:逍遥圣帝,value:我的好友,这样处理的关键是为了保存好组与好友的关系;最后再利用isHideMap来判断组的状态,如果是隐藏,则通过遍历groupMap里面的好友,使之显示,否则,反之。
4、Q:关于如何实现美化效果?
A:直接用QSS就可以了。
下面直接贴出源代码,我已经在源代码里面详细给每一个关键步骤进行了说明,所以就不进行阐述了,相信大家看得懂的,如有不懂可以追加评论,第一时间回复你们,下面是实现一个QQ好友列表的简单功能,对于其他功能大家好好拓展即可~~
一、首先是实现具有各种信息的Buddy类:
personListBuddy.h
- #ifndef PERSONLISTBUDDY_H
- #define PERSONLISTBUDDY_H
- #include <QWidget>
- #include <QLabel>
- #include <QEvent>
- //自定义信息Item类
- class personListBuddy : public QWidget
- {
- Q_OBJECT
- public:
- explicit personListBuddy(QWidget *parent = 0);
- void initUi();//初始化Ui
- QWidget *head; //头像
- QLabel *name; //用户名
- QLabel *sign; //个性签名
- QString headPath;//头像路径
- bool eventFilter(QObject *obj, QEvent *event);//事件过滤器
- signals:
- public slots:
- };
- #endif // PERSONLISTBUDDY_H
personListBuddy.cpp
- #include "personlistbuddy.h"
- #include <QPainter>
- personListBuddy::personListBuddy(QWidget *parent) :
- QWidget(parent)
- {
- initUi();
- }
- //初始化Ui
- void personListBuddy::initUi()
- {
- //初始化
- head=new QWidget(this);
- name=new QLabel(this);
- sign=new QLabel(this);
- //设置头像大小
- head->setFixedSize(40,40);
- //设置个性签名字体为灰色
- QPalette color;
- color.setColor(QPalette::Text,Qt::gray);
- sign->setPalette(color);
- //布局
- head->move(7,7);
- name->move(54,10);
- sign->move(54,27);
- //装载事件过滤器
- head->installEventFilter(this);
- }
- //事件过滤器,主要是为了让图片能够全部填充在head里面
- bool personListBuddy::eventFilter(QObject *obj, QEvent *event)
- {
- if(obj == head)
- {
- if(event->type() == QEvent::Paint)
- {
- QPainter painter(head);
- painter.drawPixmap(head->rect(), QPixmap(headPath));
- }
- }
- return QWidget::eventFilter(obj, event);
- }
二、实现好友列表personList类:
personList.h
- #ifndef PERSONLIST_H
- #define PERSONLIST_H
- #include <QListWidget>
- #include <QMenu>
- #include <QMouseEvent>
- #include <QLineEdit>
- //自定义QListWidget
- class personList : public QListWidget //继承QListWidget,可以使用它本身自带的函数,更方便
- {
- Q_OBJECT
- public:
- explicit personList(QListWidget *parent = 0);
- void mousePressEvent(QMouseEvent *event);//鼠标点击事件
- void contextMenuEvent(QContextMenuEvent*);//菜单事件,为了显示菜单
- void initMenu();//初始化菜单
- QMenu *blankMenu;//点击空白上的菜单
- QMenu *groupMenu;//点击组上的菜单
- QMenu *personMenu;//点击人上的菜单
- QMap<QListWidgetItem*,QListWidgetItem*> groupMap; // 组容器 - key:项 value:组
- QMap<QListWidgetItem*,bool> isHideMap;//用来判断该组是否隐藏了
- QLineEdit *groupNameEdit;//组的名字,重命名的时候需要用到
- QListWidgetItem *currentItem;//当前的项
- signals:
- public slots:
- void slotAddGroup(); //添加组
- void slotDelGroup(); //删除组
- void slotAddBuddy(); //添加好友
- void slotDelBuddy(); //删除好友
- void slotRename(); //重命名组
- void slotRenameEditFshed();//命名完成
- };
- #endif // PERSONLIST_H
personList.cpp
- #include "personlist.h"
- #include <QAction>
- #include <QIcon>
- #include "personlistbuddy.h"
- personList::personList(QListWidget *parent) :
- QListWidget(parent)
- {
- setFocusPolicy(Qt::NoFocus); // 去除item选中时的虚线边框
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//水平滚动条关闭
- initMenu();
- }
- //初始化菜单
- void personList::initMenu()
- {
- //初始化:
- blankMenu = new QMenu();
- groupMenu = new QMenu();
- personMenu = new QMenu();
- groupNameEdit=new QLineEdit();
- QAction *addGroup = new QAction("添加分组", this);
- QAction *delGroup = new QAction("删除该组", this);
- QAction *rename = new QAction("重命名", this);
- QAction *addBuddy = new QAction("添加好友",this);
- QAction *delBuddy = new QAction("删除好友", this);
- //设置:
- groupNameEdit->setParent(this); //设置父类
- groupNameEdit->hide(); //设置初始时隐藏
- groupNameEdit->setPlaceholderText("未命名");//设置初始时的内容
- //布局:
- blankMenu->addAction(addGroup);
- groupMenu->addAction(delGroup);
- groupMenu->addAction(rename);
- groupMenu->addAction(addBuddy);
- personMenu->addAction(delBuddy);
- //信息槽:
- connect(groupNameEdit,SIGNAL(editingFinished()),this,SLOT(slotRenameEditFshed()));
- connect(addGroup,SIGNAL(triggered()),this,SLOT(slotAddGroup()));
- connect(delGroup,SIGNAL(triggered()),this,SLOT(slotDelGroup()));
- connect(rename,SIGNAL(triggered()),this,SLOT(slotRename()));
- connect(addBuddy,SIGNAL(triggered()),this,SLOT(slotAddBuddy()));
- connect(delBuddy,SIGNAL(triggered()),this,SLOT(slotDelBuddy()));
- }
- //鼠标点击事件
- void personList::mousePressEvent(QMouseEvent *event)
- {
- QListWidget::mousePressEvent(event); // 如果不调用基类mousePressEvent,item被select会半天不响应,调用父类,让QSS起效,因为QSS基于父类QListWidget,子类就是子窗口,就是最上层窗口,是覆盖在父窗口上的,所以先于父窗口捕获消息
- //防止一种特殊情况:给新item命名、点击其他item或空白处时,指向新item的currentItem被赋予其他item
- if(groupNameEdit->isVisible() && !(groupNameEdit->rect().contains(event->pos())))
- {
- if(groupNameEdit->text()!=NULL)
- currentItem->setText(groupNameEdit->text());
- groupNameEdit->setText("");
- groupNameEdit->hide();
- }
- currentItem = this->itemAt(mapFromGlobal(QCursor::pos()));//鼠标位置的Item,不管右键左键都获取
- if(event->button()==Qt::LeftButton && currentItem!=NULL && currentItem==groupMap.value(currentItem))//如果点击的左键并且是点击的是组
- {
- if(isHideMap.value(currentItem)) //如果先前是隐藏,则显示
- {
- foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))//遍历组的对应的项(包括自身和好友)
- if(subItem!=currentItem) //如果是组的话不进行处理
- {
- subItem->setHidden(false); //好友全部显示
- }
- isHideMap.insert(currentItem,false); //设置该组为显示状态
- currentItem->setIcon(QIcon(":/arrowDown"));
- }
- else //否则,先前是显示,则隐藏
- {
- foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))//遍历组的对应的项(包括自身和好友)
- if(subItem!=currentItem) //如果是组的话不进行处理
- {
- subItem->setHidden(true); //好友全部隐藏
- }
- isHideMap.insert(currentItem,true); //设置该组为隐藏状态
- currentItem->setIcon(QIcon(":/arrowRight"));
- }
- }
- }
- //菜单事件,为了显示菜单,点击鼠标右键响应,鼠标点击事件mousePressEvent优先于contextMenuEvent
- void personList::contextMenuEvent(QContextMenuEvent *event)
- {
- QListWidget::contextMenuEvent(event); //调用基类事件
- if(currentItem==NULL) //如果点击到的是空白处
- {
- blankMenu->exec(QCursor::pos());
- return;
- }
- if(currentItem==groupMap.value(currentItem)) // 如果点击到的是组
- groupMenu->exec(QCursor::pos());
- else //否则点击到的是好友
- personMenu->exec(QCursor::pos());
- }
- //添加组
- void personList::slotAddGroup()
- {
- QListWidgetItem *newItem=new QListWidgetItem(QIcon(":/arrowRight"),"未命名"); //创建一个Item
- newItem->setSizeHint(QSize(this->width(),25));//设置宽度、高度
- this->addItem(newItem); //加到QListWidget中
- groupMap.insert(newItem,newItem);//加到容器groupMap里,key和value都为组
- isHideMap.insert(newItem,true); //设置该组隐藏状态
- groupNameEdit->raise();
- groupNameEdit->setText(tr("未命名")); //设置默认内容
- groupNameEdit->selectAll(); //设置全选
- groupNameEdit->setGeometry(this->visualItemRect(newItem).left()+15,this->visualItemRect(newItem).top()+1,this->visualItemRect(newItem).width(),this->visualItemRect(newItem).height()-2);//出现的位置
- groupNameEdit->show(); //显示
- groupNameEdit->setFocus(); //获取焦点
- currentItem = newItem; // 因为要给group命名,所以当前的currentItem设为该group
- }
- //删除组
- void personList::slotDelGroup()
- {
- foreach(QListWidgetItem* item, groupMap.keys(currentItem)) //遍历该组的所有好友和自身的组
- {
- groupMap.remove(item); //移除
- delete item; //删除
- }
- isHideMap.remove(currentItem); //移除
- }
- //重命名
- void personList::slotRename()
- {
- groupNameEdit->raise();
- groupNameEdit->setGeometry(this->visualItemRect(currentItem).left()+15,this->visualItemRect(currentItem).top()+1,this->visualItemRect(currentItem).width(),this->visualItemRect(currentItem).height()-2);//出现的位置
- groupNameEdit->setText(currentItem->text()); //获取该组名内容
- groupNameEdit->show(); //显示
- groupNameEdit->selectAll(); //全选
- groupNameEdit->setFocus(); //获取焦点
- }
- //添加好友,主要是为了测试功能,实际工程里可以改成动态读取数据库进行添加好友
- void personList::slotAddBuddy()
- {
- personListBuddy *buddy=new personListBuddy(); //创建一个自己定义的信息类
- buddy->headPath=":/head"; //设置头像路径
- buddy->name->setText("逍遥圣帝"); //设置用户名
- buddy->sign->setText("用通俗的语言,讲深刻的技术。"); //设置个性签名
- QList<QListWidgetItem*> tem = groupMap.keys(currentItem);//当前组对应的项(包括组本身和好友)复制给tem
- //关键代码
- QListWidgetItem *newItem = new QListWidgetItem(); //创建一个newItem
- this->insertItem(row(currentItem)+tem.count(),newItem); //将该newItem插入到后面
- this->setItemWidget(newItem, buddy); //将buddy赋给该newItem
- groupMap.insert(newItem,currentItem); //加进容器,key为好友,value为组
- if(isHideMap.value(currentItem)) //如果该组是隐藏,则加进去的好友设置为隐藏
- newItem->setHidden(true);
- else //否则,该好友设置为显示
- newItem->setHidden(false);
- }
- //删除好友
- void personList::slotDelBuddy()
- {
- groupMap.remove(currentItem); //移除该好友
- delete currentItem; //删除
- }
- //重命名完成
- void personList::slotRenameEditFshed()
- {
- if(groupNameEdit->text()!=NULL) //如果重命名编辑框不为空
- currentItem->setText(groupNameEdit->text()); //更新组名
- groupNameEdit->setText("");
- groupNameEdit->hide(); //隐藏重命名编辑框
- }
三、美化用到的QSS:
- QListWidget{
- background:white;
- color:black;
- border:none;
- }
- QListWidget::item{
- border:none;
- height: 54px;
- }
- QListWidget::item:hover{
- background:rgb(252,240,193)
- }
- QListWidget::item:selected{
- background:rgb(252,233,161);
- color:black;
- }
- QScrollBar:vertical {
- background:transparent;
- width:9px;
- margin: 0px 0px 2px 0px;
- }
- QScrollBar::handle:vertical {
- background: rgb(195, 195, 195);
- min-height: 20px;
- border-radius: 3px;
- }
- QScrollBar::handle:vertical:hover{
- background:rgba(0,0,0,30%);
- }
- QScrollBar::add-line:vertical {
- height: 0px;
- subcontrol-position: bottom;
- subcontrol-origin: margin;
- }
- QScrollBar::sub-line:vertical {
- height: 0px;
- subcontrol-position: top;
- subcontrol-origin: margin;
- }
四、用到的素材:
五、效果图:
Qt实现QListView自定义Item界面——仿QQ好友界面相关推荐
- java仿qq 界面_界面--仿qq登录界面
[java]代码库package s1127qq登陆界面; import java.awt.BorderLayout; import java.awt.Color; import java.awt.C ...
- android自定义设置界面,Android开发之精仿QQ设置界面(自定义PreferenceActivity)
Android开发之精仿QQ设置界面(自定义PreferenceActivity) 时间:2011-12-05 10:25:06 来源:Android开发者门户 作者: 今天,再给大家分享一下QQ设置 ...
- INNO 仿QQ安装界面
INNO 仿QQ安装界面 鉴于很多网友需要该脚本,csdn的现在下载分比较高,博主建了个群,大家可以在群里下载这个脚本,主要功能实现了,大家可以自行完善. 加入QQ群:632012850 先上图片 1 ...
- java仿qq登录 界面设计,Java Swing仿QQ登录界面效果
本文实例为大家分享了Java Swing仿QQ登录界面展示的具体代码,供大家参考,具体内容如下 闲来无事将早些时候已实现的QQ登录界面再实现了一遍,纯手工打造(意思是没有用NetBeans.MyEcl ...
- java如何引入qq登陆,Java Swing仿QQ登录界面 学习之用
闲来无事将早些时候已实现的QQ登录界面再实现了一遍,纯手工打造(意思是没有用NetBeans.MyEclipse的拖动功能). 源代码如下: package ibees.qq; import java ...
- 名片夹android布局代码,Android自定义布局实现仿qq侧滑部分代码
自定义布局实现仿qq侧滑部分Android代码,供大家参考,具体内容如下 实现说明: 通过自定义布局实现: SlidingLayout继承于 HorizontalScrollView /** * Cr ...
- Android自定义View之仿QQ运动步数进度效果
文章目录 前言 先看效果图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e4ddec17933496ea4830fa08d8ffbe5.png?x-oss-pr ...
- java gui界面设计qq_Java swing界面开发(仿QQ登录界面)
首先引入包的概念,包:给代码分类,提高的了代码的可读性,封装后方便管理.在包中类的引入:import 包名.类名;包名需小写,多单词用"."隔开.类名的命名规范:首字母大写其后的每 ...
- qt小项目 代码实现简易的QQ聊天界面
qt小项目 代码实现简易的QQ聊天界面 代码 效果图 总结 代码 myDialog.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QW ...
最新文章
- CakePHP中出现persistent is not writable等Warning的解决方法
- 五分钟搭建BERT服务,实现1000+QPS​,这个Service-Streamer做到了
- 【BZOJ】P2144 跳跳棋
- 1.3 Java二维数组详解
- ELK三件套安装实践之路(1)
- 微博json文件_python 爬取微博评论 !
- java基础之多态的详细解释_JAVA基础之多态
- Oracle Sql 胡乱记
- 人类如何感受到四维空间?
- PHP笔记-自定义MVC框架
- 5 仓库号xxx的主数据仍然现存不能删除(慎用)
- Android Webview SSL 自签名安全校验解决方案
- 苹果mac视觉效果和动态图形设计软件:After Effects 2022 (ae 2022)
- 学习笔记1/5,操作系统之操作系统概念
- 机器学习-随机森林算法
- Spring Boot 阿里云短信平台手机验证码测试
- 压缩word文档大小的方法?
- 彼得林奇的成功投资 (修订版)
- lga2066服务器准系统,4094个针脚,AMD 16核桌面处理器插槽比LGA2066还要大
- 多核 CPU 和多个 CPU 有何区别?与线程的关系?