频道栏目
首页 > 程序开发 > 软件开发 > 其他 > 正文
Qt 之 QQ系统表情(五)
2016-09-08 09:33:03         来源:前行中的小猪  
收藏   我要投稿

简述

在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();
    //恢复原来的margin
    setContentsMargins(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 !

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

点击复制链接 与好友分享!回本站首页
相关TAG标签 Qt QQ系统表情
上一篇:最大流问题
下一篇:带你玩转Visual Studio——调用约定与(动态)库
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站