关闭

Qt 之 QQ系统表情(四)

标签: qtqq表情
1016人阅读 评论(1) 收藏 举报
分类:

简述

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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    博客介绍

    前行中的小猪!


    博客主要包含了Qt学习的一些基础内容,欢迎大家一起交流、讨论。


    博客将会不断更新,更多精彩、好玩的内容等着你!


    文章中的大图被压缩可能不是很清晰,可以放大网页进行浏览

    Qt 分享交流

    Qt 学习、爱好者 欢迎一起交流!

    群号:311750285
    个人资料
    • 访问:168006次
    • 积分:2643
    • 等级:
    • 排名:第15480名
    • 原创:72篇
    • 转载:0篇
    • 译文:1篇
    • 评论:197条
    最新评论