Qt 之 QQ系统表情(四)
来源:互联网 发布:大芒果魔兽数据库 编辑:程序博客网 时间:2024/05/21 15:39
简述
继Qt 之 QQ系统表情(三) 中我们用了两种方法实现了当前鼠标位置的表情动态显示,在这一篇中我们将对其进行拓展,增加一些新特效以及能够自定义表情窗口(包括表情的行列数 , 表情的大小,表情的个数、最大行数等)。好了,话不多说,代码走起。
代码之路
在Qt 之 QQ系统表情(三) 中,我们通过nativeEvent事件捕捉鼠标的位置,根据鼠标的位置判断在QTableWidget中的哪一个item上,但是nativeEvent事件会受到一定的限制,见下图。
从Qt文档中可以看出,只有在一个拥有本地窗口句柄的widget中,事件才可以被传递到nativeEvent中。比如我们继承了QTableWidget(命名为MyEmotionWidget),在MyEmotionWidget中重写了nativeEvent事件,而MyEmotionWidget又在其他窗口widget中作为一个成员变量(本身不具有窗口句柄),则nativeEvent事件不会接受到外部的事件。
怎么办呢?
靠,直接在有窗口句柄的widget中重写nativeEvent事件,再将鼠标当前的位置传递给MyEmotionWidget不就OK了,so 上代码。
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); QLabel* emotionIcon = new QLabel; emotionIcon->setContentsMargins(3, 3, 3, 3); // 设置鼠标悬浮时显示蓝色边框; emotionIcon->setStyleSheet("QLabel:hover{border: 1px solid rgb(111, 156, 207);\ color: rgb(2, 65, 132);\ background: rgba(255, 255, 255, 200);}"); QMovie* movie = new QMovie; movie->setScaledSize(QSize(24, 24)); movie->setFileName(fileName); // start and stop 后图片显示正常; movie->start(); movie->stop(); emotionIcon->setMovie(movie); this->setCellWidget(row, column, emotionIcon); m_emotionList.push_back(fileName);}// 因为MyEmotionWidget作为子部件来使用,故nativeEvent接收不到事件,这里由外部调用传入鼠标在父部件的位置void MyEmotionWidget::showDynamicEmotion(QPoint cursorPos){ // 当前传入的为鼠标在父控件上的位置,所以还需要减去tableWidget在父控件上的位置,其结果为鼠标在tableWidget的位置 QPoint point = cursorPos - this->pos(); QTableWidgetItem* tableWidgetItem = this->itemAt(point); if (tableWidgetItem != NULL) { //如果获取到的item不为空说明此刻鼠标所在的区域在tableWidget的某个item中, //并且如果鼠标从一个表情移动到一个其他未设置item的单元格或者移出tableWidget区域 //在同一个item中移动则不做任何操作; if (m_preRow != tableWidgetItem->row() || m_preColumn != tableWidgetItem->column()) { QLabel* preEmotion = (QLabel*)this->cellWidget(m_preRow, m_preColumn); if (preEmotion != NULL) { //恢复原来的margin preEmotion->setContentsMargins(3, 3, 3, 3); QMovie* preMoive = preEmotion->movie(); preMoive->jumpToFrame(0); preMoive->stop(); } QLabel* curEmotion = (QLabel*)this->cellWidget(tableWidgetItem->row(), tableWidgetItem->column()); if (curEmotion != NULL) { // 当鼠标悬浮在item上时修改margin值达到表情切换效果,见下图(在鼠标从一个表情滑到另一个表情时) curEmotion->setContentsMargins(4, 2, 2, 4); QMovie* curMoive = curEmotion->movie(); curMoive->start(); m_preRow = tableWidgetItem->row(); m_preColumn = tableWidgetItem->column(); } } } else { //如果获取到的item为空说明此刻鼠标所在的区域不在tableWidget的items中, //并且如果鼠标刚从一个动态表情移动到一个其他未设置item的单元格或者移出tableWidget区域, //则根据上一个表情的位置获取到item并停止正在动态显示的表情,并将m_preRow、m_preColumn置为-1, //以免下次再次进入到此分支进行重复操作; QTableWidgetItem* tableWidgetItem = this->item(m_preRow, m_preColumn); if (tableWidgetItem != NULL) { QLabel* preEmotion = (QLabel*)this->cellWidget(m_preRow, m_preColumn); if (preEmotion != NULL) { //恢复原来的margin preEmotion->setContentsMargins(3, 3, 3, 3); QMovie* preMoive = preEmotion->movie(); preMoive->jumpToFrame(0); preMoive->stop(); m_preRow = -1; m_preColumn = -1; } } }}
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事件bool EmotionWindow::nativeEvent(const QByteArray &eventType, void *message, long *result){ MSG* msg = reinterpret_cast<MSG*>(message); switch (msg->message) { case WM_MOUSEMOVE: { // 将鼠标在EmotionWindow上的坐标传递到表情窗口中 QPoint point = QCursor::pos() - this->pos(); m_normalEmotionWidget->showDynamicEmotion(point); m_smallEmotionWidget->showDynamicEmotion(point); } } return __super::nativeEvent(eventType, message, result);}
// 显示表情窗口EmotionWindow w;w.showSmallEmotion(QPoint(500 , 500));//w.showNormalEmotion(QPoint(500 , 500));
小表情框
正常表情框
尾
功夫不负有心人,到此我们已经通过nativeEvent方法实现了自定义表情窗口。大家可以看到可以自定义表情窗口的行列数、表情数目,最大行数等,下一篇将通过重写QLabel的方式完成自定义表情窗口。
加油,前行中的Small Pig !!!
1 0
- Qt 之 QQ系统表情(四)
- Qt 之 QQ系统表情(一)
- Qt 之 QQ系统表情(二)
- Qt 之 QQ系统表情(三)
- Qt 之 QQ系统表情(五)
- Qt 之 QQ系统表情—实现动态显示效果
- qq表情实现之二
- 【Qt】仿QQ表情选择控件
- Android开发之仿QQ表情实现(上)
- Android开发之仿QQ表情实现(下)
- MSN / QQ 中的CRichEditCtrl (四) —— 动画表情(Full Source Code)
- QQ表情
- Qt仿QQ界面,主界面、聊天界面、表情界面
- QQ表情 QQ图片 QQ图像制作方法(一)
- Qt之QQ登录界面(一)
- Qt之QQ登录界面(二)
- Qt之QQ登录界面(三)
- servlet之qq四
- 两台笔记本屏幕扩展
- MYSQL数据库语句之其他(四)
- 带你跳出H5输入框input的坑
- WebView的基本常用属性 及方法
- 系统服务管理
- Qt 之 QQ系统表情(四)
- Android Studio中commit时的用户名修改
- adb的几个简单命令
- js控制手机号码间隔输入
- Linux下的常用终端命令
- libjingle源码解析(5)-【PseudoTcp】建立UDP之上的TCP(3):对成块数据流的处理
- 【Android】SlidingTabLayout实现标题栏,教你制作title标题 简单易学。
- TCP协议中的三次握手和四次挥手(图解) .
- 实验测试注意事项