简述

在Qt 之 QQ系统表情(四) 中我们通过用nativeEvent事件的方法实现了自定义表情窗口,这一篇将通过继承QLabel的方式来实现。同时我也在研究过程中发现了一些小问题。

代码Go!

代码之路


MyEmotionItemWidget.cpp

MyEmotionItemWidget::MyEmotionItemWidget(QString fileName , QSize emotionMoiveSize): QLabel(NULL)
{//首先构造函数中进行初始化;QMovie* iconMovie = new QMovie;iconMovie->setFileName(fileName);this->setMovie(iconMovie);setContentsMargins(3, 3, 3, 3);iconMovie->setScaledSize(QSize(emotionMoiveSize.width(), emotionMoiveSize.height()));//为了动态图片正常显示,(不加上start图片不显示,不加上stop图片一种处于动态效果)iconMovie->start();iconMovie->stop();setStyleSheet("QLabel:hover{border: 1px solid rgb(111, 156, 207);\background: rgba(255, 255, 255, 200);}");
}MyEmotionItemWidget::~MyEmotionItemWidget()
{}// 鼠标进入Label事件
void MyEmotionItemWidget::enterEvent(QEvent* event)
{QMovie* movie = this->movie();movie->start();// 当鼠标悬浮在item上时修改margin值达到表情切换效果,见下图(在鼠标从一个表情滑到另一个表情时)setContentsMargins(4, 2, 2, 4);return __super::enterEvent(event);
}
// 鼠标离开Label事件
void MyEmotionItemWidget::leaveEvent(QEvent* event)
{QMovie* movie = this->movie();movie->jumpToFrame(0);movie->stop();//恢复原来的marginsetContentsMargins(3, 3, 3, 3);return __super::leaveEvent(event);
}

MyEmotionWidget.cpp

MyEmotionWidget::MyEmotionWidget(QWidget *parent): QTableWidget(parent), m_tableRow(0), m_tableColumn(0), m_preRow(0), m_preColumn(0), m_maxRow(6), m_emotionSize(QSize(0 , 0)), m_emotionMovieSize(QSize(0 , 0))
{loadStyleSheet();
}MyEmotionWidget::~MyEmotionWidget()
{}// 直接从文件中获取样式
void MyEmotionWidget::loadStyleSheet()
{QFile file(":/Resources/QSS/myemotion.css");file.open(QFile::ReadOnly);QString strSheet = file.readAll();QString styleSheet = this->styleSheet();styleSheet += strSheet;this->setStyleSheet(styleSheet);
}
// 设置表情窗口的行列数目
void MyEmotionWidget::setRowAndColumn(int row, int column)
{m_tableRow = row;m_tableColumn = column;
}
// 设置item表情框大小
void MyEmotionWidget::setEmotionSize(QSize emotionSize)
{m_emotionSize = emotionSize;
}
// 设置表情movie大小
void MyEmotionWidget::setEmotionMovieSize(QSize emotionMovieSize)
{m_emotionMovieSize = emotionMovieSize;
}
// 设置最大行数
void MyEmotionWidget::setMaxRow(int maxRow)
{m_maxRow = maxRow;
}
// 设置完参数后,进行初始化
void MyEmotionWidget::initTableWidget()
{// 设置无焦点this->setFocusPolicy(Qt::NoFocus);// 设置不可编辑this->setEditTriggers(QAbstractItemView::NoEditTriggers);// 设置行数this->setRowCount(m_tableRow);// 设置列数this->setColumnCount(m_tableColumn);// 设置表头不可见并设置表情item框大小this->horizontalHeader()->setVisible(false);this->horizontalHeader()->setDefaultSectionSize(m_emotionSize.width());this->verticalHeader()->setVisible(false);this->verticalHeader()->setDefaultSectionSize(m_emotionSize.height());// 设置表情窗口的大小,这里行数超过m_maxRow时作了处理,当行数超过给的最大值,则通过滚动 滚动条显示剩余的表情if (m_tableRow > m_maxRow){this->setFixedHeight(m_emotionSize.height()*m_maxRow+ 2);// 这里宽度加30,是因为在这种情况下会tablewidget会显示出滚动条,所以为了显示正常,增加一点宽度this->setFixedWidth(m_emotionSize.width()*m_tableColumn + 30);}else{this->setFixedHeight(m_emotionSize.height()*m_tableRow + 2);this->setFixedWidth(m_emotionSize.width()*m_tableColumn + 2);}
}void MyEmotionWidget::addEmotionItem(QString fileName , QString toolTip)
{int row = m_emotionList.size() / this->columnCount();int column = m_emotionList.size() % this->columnCount();QTableWidgetItem* tableWidgetItem = new QTableWidgetItem;tableWidgetItem->setToolTip(toolTip);this->setItem(row, column, tableWidgetItem);MyEmotionItemWidget* emotionIcon = new MyEmotionItemWidget(fileName , m_emotionMovieSize);this->setCellWidget(row, column, emotionIcon);m_emotionList.push_back(fileName);
}

EmotionWindow.cpp

EmotionWindow::EmotionWindow(QWidget *parent): QWidget(parent), m_smallEmotionWidget(NULL), m_normalEmotionWidget(NULL)
{ui.setupUi(this);initWindow();initEmotion();
}
EmotionWindow::~EmotionWindow()
{}void EmotionWindow::initWindow()
{this->setWindowFlags(Qt::FramelessWindowHint);this->setStyleSheet("background:rgb(220, 240, 160);");
}// 初始化表情窗口
void EmotionWindow::initEmotion()
{// 初始化小表情框m_smallEmotionWidget = new MyEmotionWidget;m_smallEmotionWidget->setRowAndColumn(4, 4);m_smallEmotionWidget->setEmotionSize(QSize(32, 32));m_smallEmotionWidget->setEmotionMovieSize(QSize(24, 24));m_smallEmotionWidget->setMaxRow(4);m_smallEmotionWidget->initTableWidget();//表情的路径QString path = ":\\Resources\\QQexpression\\%1.gif";for (int i = 0; i < 10; i++){m_smallEmotionWidget->addEmotionItem(path.arg(i + 1), "");}// 初始化正常表情框;m_normalEmotionWidget = new MyEmotionWidget;m_normalEmotionWidget->setRowAndColumn(10, 14);m_normalEmotionWidget->setEmotionSize(QSize(32, 32));m_normalEmotionWidget->setEmotionMovieSize(QSize(24, 24));m_normalEmotionWidget->setMaxRow(6);m_normalEmotionWidget->initTableWidget();for (int i = 0; i < 132; i++){m_normalEmotionWidget->addEmotionItem(path.arg(i + 1), "");}// 初始化样式m_lableTitle = new QLabel;QVBoxLayout* vLayout = new QVBoxLayout;vLayout->addWidget(m_lableTitle);vLayout->addWidget(m_smallEmotionWidget);vLayout->addWidget(m_normalEmotionWidget);this->setLayout(vLayout);
}
// 显示小表情窗口
void EmotionWindow::showSmallEmotion(QPoint point)
{m_normalEmotionWidget->setVisible(false);m_lableTitle->setText("This is Small Emotion Window");this->setFixedSize(QSize(m_smallEmotionWidget->width() + 20, m_smallEmotionWidget->height() + 50));move(point);show();
}
// 显示大表情窗口
void EmotionWindow::showNormalEmotion(QPoint point)
{m_smallEmotionWidget->setVisible(false);m_lableTitle->setText("This is Normal Emotion Window");this->setFixedSize(QSize(m_normalEmotionWidget->width() + 20, m_normalEmotionWidget->height() + 50));move(point);show();
}

叙:

相比上一篇使用nativeEvent的方法,通过继承QLabel的方式显得代码更加清爽、简单、方便,相对而言这种方法更胜一筹,同时在使用nativeEvent的方法实现的表情框中出现了两个小小的问题,见下图。


nativeEvent的方法实现

问题一

从图一中可以看出当鼠标悬浮在上下两个表情之间的边框上时,这个时候鼠标的位置实际上是在tableWidget上了,所以此时程序中并没有判断出鼠标移动到另一个表情中,所以下面这个表情一直保持动态显示,与此同时鼠标又不在label上,动态显示的表情就不会显示蓝色的边框。

问题二

仔细看最右边的表情,当鼠标离开这个表情窗口,表情仍然动态显示,检查代码,发现通过nativeEvent捕捉WM_MOUSEMOVE(鼠标移动)事件时,当鼠标移出窗口就不会捕捉,所以当鼠标快速移出窗口之外,同时由于tableWidget最右方与窗口的边距很小,导致未能够及时捕捉到鼠标的移动,所以导致鼠标在窗口之外,表情仍然动态显示。

从这里也可以看出,当鼠标快速移动时,nativeEvent并不会因为鼠标每移动一个像素点就捕捉一次鼠标移动信号,更类似于当鼠标不断移动过程中,nativeEvent会每隔一段时间捕捉鼠标移动(当然这一段时间非常小,基于毫秒级别)。
同时对于mouseMoveEvent事件同样如此,而nativeEvent会先于mouseMoveEvent捕捉到鼠标移动(或者说nativeEvent捕捉到的任何事件都会先于Qt中的事件,具体看Qt助手)。

好了接下来看一看QLabel实现的效果图

验证问题一:

验证问题二:


经过验证,使用继承QLabel方式解决了以上两个“小问题”,如果观察的不够仔细的话这两个小问题不一定会被发现,从另一个角度可以看出我对代码细心研究的态度。不过因当前水平有限,可能代码中也存在一些问题未被发现。So Keep Moving !

进步始于交流,收获源于分享。欢迎大家能够一起交流^_^。


下载

Qt 之实现 QQ系统表情窗口

Qt 之 QQ系统表情(五)相关推荐

  1. Vc++ - qt -仿照微信项目- 表情窗口设计

    分享的力量是无穷的,在csdn上搜索关于表情窗口的设计,偶然发现之前有人做过关于表情这方面的工作,博主:前行中的小猪,相关系列文章 <<QQ之系统表情>>,这里提供<&l ...

  2. Qt工作笔记-Qt元对象系统解析【2合1】

    博文转载地址: https://blog.csdn.net/spwper/article/details/51332187 说Qt信号与槽是一个很好机制,不如说Qt的元对象系统很强大.这也是大家讲Qt ...

  3. Qt模仿QQ聊天窗口界面(二)

    Qt模仿QQ聊天窗口界面(二) Qt模仿QQ聊天窗口界面(二) 简述 修改 效果图 后期规划 代码 结尾 简述 在上篇我们已经搭好了QQ聊天窗口的框架,这里在原来的基础上叠加功能,以及优化一些控件. ...

  4. 2021年春季学期-信号与系统-第五次作业参考答案-第十一移小题—MATLAB

    本文是 2021年春季学期-信号与系统-第五次作业参考答案 中的小题解答. ▌第十一题:MABLAT 在MATLAB中,根据矩形周期脉冲信号傅里叶级数分解也锯齿波傅里叶级数分解的公式,绘制前N项级数叠 ...

  5. 2021年春季学期-信号与系统-第五次作业参考答案-第十小题

    本文是 2021年春季学期-信号与系统-第五次作业参考答案 中的小题解答. ▌第十题 10. 利用傅里叶变换公式计算下面信号的傅里叶变换. (1) e−2(t−1)⋅u(t−1)e^{ - 2\lef ...

  6. 2021年春季学期-信号与系统-第五次作业参考答案-第九小题

    本文是 2021年春季学期-信号与系统-第五次作业参考答案 中的小题解答. ▌第九题 9. 求下图所示的半波余弦脉冲的傅里叶变换, 并画出频谱图: 注:对于该信号的频谱计算,可以直接利用公式进行.其中 ...

  7. 2021年春季学期-信号与系统-第五次作业参考答案-第八小题

    本文是 2021年春季学期-信号与系统-第五次作业参考答案 中的小题解答. ▌第八题 8. 关于周期信号x(t)x\left( t \right)x(t)有如下相应的描述: (1) x(t)x\lef ...

  8. 2021年春季学期-信号与系统-第五次作业参考答案-第七小题

    本文是 2021年春季学期-信号与系统-第五次作业参考答案 中的小题解答. ▌第七题 7. 利用信号的对称性,确定下面各个周期信号的傅里叶级数所含有的频率成分: ※ 求解: (1)第一小题 偶对称.奇 ...

  9. 2021年春季学期-信号与系统-第五次作业参考答案-第六小题

    本文是 2021年春季学期-信号与系统-第五次作业参考答案 中的小题解答. ▌第六题 6. 已知周期信号 f(t)f\left( t \right)f(t)在其四分之一周期内的信号波形如下图所示: 分 ...

  10. 2021年春季学期-信号与系统-第五次作业参考答案-第五小题

    本文是 2021年春季学期-信号与系统-第五次作业参考答案 中的小题解答. ▌第五题 5. 设 f(t)f\left( t \right)f(t)为 [−π,π]\left[ { - \pi ,\pi ...

最新文章

  1. 智能合约重构社会契约(11)天德区块链智能合约系统
  2. leetcode 201. Bitwise AND of Numbers Range(位运算,dp)
  3. 能使曲线变平滑的一维滤波器_双边滤波器的原理及实现
  4. 免费时代的4种销售方式
  5. Python for循环 - Python零基础入门教程
  6. Spring AOP源码解析——专治你不会看源码的坏毛病!
  7. java ocr linux_linux系统如何使用tess4j(java)进行ocr图片文字识别
  8. 远程管理软件Royal TSX for Mac
  9. 找到没使用过的ip地址
  10. 移动办公平台忘记密码怎么办?移动办公平台下载
  11. ECShop 批量打印快递单
  12. java 调用ffmpeg 转成mp4_Java+Windows+ffmpeg实现视频转换
  13. 最新北京人才公寓申请流程,技术员的福利~
  14. 剑指offer算法题分析与整理(二)
  15. Android 意图(Intent)和过滤器(Filter)
  16. 机器学习项目案例 简单的数字验证码自动识别
  17. typora+阿里云图床+印象笔记+OneDrive安全保存你的文章
  18. python多核运行程序_python单进程能否利用多核cpu的测试结论
  19. DHCP 服务原理与配置
  20. 数组----一维数组

热门文章

  1. Maven镜像源汇总(含国内、国外)
  2. uniapp手写_uniapp 手写 Steps 步骤条
  3. 一次完整的HTTP请求过程(深入分析)
  4. DVBS卫星识别流程
  5. 如何测试webservice接口
  6. springboot集成webservice接口
  7. PIC24HJ单片机的UART
  8. 带通 带阻滤波器 幅频响应_方程推导:二阶有源带通滤波器设计!(内附教程+原理图+视频+代码下载)...
  9. LTE时域、频域资源
  10. JSP基础教程【1】