Qt模仿QQ聊天窗口界面(一)

简述

最近利用业余时间,模仿QQ做了一个聊天窗口界面,功能还不全,准备分几个部分做出来,还是看空闲时间了,以及广大网友的支持了。

效果图

QQ的聊天窗口

这里写图片描述

我做的效果图

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

代码篇

//TalkWindowShell.cpp
TalkWindowShell::TalkWindowShell(QWidget *parent)
    : BasicWindow(parent)
{
    ui.setupUi(this);
    initControl();

    {
        TalkWindow* talkwindow1 = new TalkWindow(this);
        TalkWindowItem* talkwindowItem1 = new TalkWindowItem(talkwindow1);
        talkwindow1->setWindowName(QStringLiteral("雨田哥-工作号-1号"));
        talkwindowItem1->setMsgLabelContent(QStringLiteral("雨田哥-1号"));
        talkwindow1->setWindowSignName(QStringLiteral("欢迎吐槽、雨田哥-工作号-1号"));
        addTalkWindow(talkwindow1, talkwindowItem1);
    }

    {
        TalkWindow* talkwindow2 = new TalkWindow(this);
        TalkWindowItem* talkwindowItem2 = new TalkWindowItem(talkwindow2);
        talkwindow2->setWindowName(QStringLiteral("雨田哥-工作号-2号-2号"));
        talkwindowItem2->setMsgLabelContent(QStringLiteral("雨田哥-2号"));
        talkwindow2->setWindowSignName(QStringLiteral("欢迎吐槽、雨田哥-工作号-2号-2号"));
        addTalkWindow(talkwindow2, talkwindowItem2);
    }

    {
        TalkWindow* talkwindow3 = new TalkWindow(this);
        TalkWindowItem* talkwindowItem3 = new TalkWindowItem(talkwindow3);
        talkwindow3->setWindowName(QStringLiteral("雨田哥-工作号-3号-3号-3号"));
        talkwindowItem3->setMsgLabelContent(QStringLiteral("雨田哥-3号"));
        talkwindow3->setWindowSignName(QStringLiteral("欢迎吐槽、雨田哥-工作号-3号-3号-3号"));
        addTalkWindow(talkwindow3, talkwindowItem3);
    }
}

TalkWindowShell::~TalkWindowShell()
{
    delete m_emotionWindow;
    m_emotionWindow = nullptr;
}

void TalkWindowShell::initControl()
{
    loadStyleSheet("TalkWindow");

    m_emotionWindow = new EmotionWindow;
    m_emotionWindow->hide();

    QList leftWidgetSize;
    leftWidgetSize << 154 << width() - 154;
    ui.splitter->setSizes(leftWidgetSize);

    ui.listWidget->setStyle(new CustomProxyStyle(this));

    connect(ui.listWidget, &QListWidget::itemClicked, this, &TalkWindowShell::onTalkWindowItemClicked);
    connect(m_emotionWindow, SIGNAL(signalEmotionItemClicked(int)), this, SLOT(onEmotionItemClicked(int)));
}

void TalkWindowShell::onEmotionBtnClicked(bool)
{
    m_emotionWindow->setVisible(!m_emotionWindow->isVisible());
    QPoint emotionPoint = this->mapToGlobal(QPoint(0, 0));
    emotionPoint.setX(emotionPoint.x() + 170);
    emotionPoint.setY(emotionPoint.y() + 220);
    m_emotionWindow->move(emotionPoint);
}

void TalkWindowShell::onTalkWindowItemClicked(QListWidgetItem *item)
{
    QWidget* talkwindowWidget = m_talkwindowItemMap.find(item).value();
    ui.rightStackedWidget->setCurrentWidget(talkwindowWidget);
}

void TalkWindowShell::addTalkWindow(TalkWindow* talkwindow, TalkWindowItem* talkwindowitem)
{
    ui.rightStackedWidget->addWidget(talkwindow);
    connect(m_emotionWindow, SIGNAL(signalEmotionWindowHide()), talkwindow, SLOT(onSetEmotionBtnStatus()));

    QListWidgetItem *aItem = new QListWidgetItem(ui.listWidget);
    m_talkwindowItemMap.insert(aItem, talkwindow);

    aItem->setSelected(true);
    talkwindowitem->setHeadPixmap("");
    ui.listWidget->addItem(aItem);
    ui.listWidget->setItemWidget(aItem, talkwindowitem);

    onTalkWindowItemClicked(aItem);

    connect(talkwindowitem, &TalkWindowItem::signalCloseClicked, [talkwindowitem, talkwindow, aItem, this](){
        m_talkwindowItemMap.remove(aItem);
        talkwindow->close();
        ui.listWidget->takeItem(ui.listWidget->row(aItem));
        delete talkwindowitem;
        ui.rightStackedWidget->removeWidget(talkwindow);
        if (ui.rightStackedWidget->count() < 1)
            close();
    });
}

void TalkWindowShell::onEmotionItemClicked(int emotionNum)
{
    TalkWindow* curTalkWindow = dynamic_cast(ui.rightStackedWidget->currentWidget());
    if (curTalkWindow)
    {
        curTalkWindow->addEmotionImage(emotionNum);
    }
}
TalkWindow.cpp
TalkWindow::TalkWindow(QWidget *parent)
    : QWidget(parent)
{
    setAttribute(Qt::WA_DeleteOnClose);
    ui.setupUi(this);
    initControl();
}

TalkWindow::~TalkWindow()
{

}

void TalkWindow::initControl()
{
    setSendBtnMenu();
    QList rightWidgetSize;
    rightWidgetSize << 600 << 138;
    ui.bodySpliter->setSizes(rightWidgetSize);

    connect(ui.sysmin, SIGNAL(clicked(bool)), parent(), SLOT(onShowMin(bool)));
    connect(ui.sysclose, SIGNAL(clicked(bool)), parent(), SLOT(onShowClose(bool)));
    connect(ui.closeBtn, SIGNAL(clicked(bool)), parent(), SLOT(onShowClose(bool)));

    connect(ui.faceBtn, SIGNAL(clicked(bool)), parent(), SLOT(onEmotionBtnClicked(bool)));
    connect(ui.sendBtn, SIGNAL(clicked(bool)), this, SLOT(onSendBtnClicked(bool)));

    ui.msgWidget->setShowSkinControl(ui.skinLabel);
}

void TalkWindow::onSetEmotionBtnStatus()
{
    ui.faceBtn->setChecked(false);
}

void TalkWindow::setWindowName(const QString& name)
{
    ui.nameLabel->setText(name);
}

void TalkWindow::setWindowSignName(const QString& name)
{
    ui.signLabel->setText(name);
}

void TalkWindow::onSignalWindowclosed()
{
    close();
}

void TalkWindow::onSendBtnClicked(bool)
{
    ui.textEdit->clear();
    ui.textEdit->delteAllEmotionImage();

    MsgWidgetItem* msgItem = new MsgWidgetItem(this);
    int count = ui.msgLayout->count();
    ui.msgLayout->insertWidget(count - 1, msgItem);
}

void TalkWindow::addEmotionImage(int emotionNum)
{
    ui.textEdit->setFocus();
    ui.textEdit->addEmotionUrl(emotionNum);
}

void TalkWindow::setSendBtnMenu()
{
    QMenu* menu = new QMenu(this);
    menu->setWindowFlags(menu->windowFlags() | Qt::FramelessWindowHint);
    menu->setAttribute(Qt::WA_TranslucentBackground);
    menu->setObjectName("senMenu");
    m_sendAction = menu->addAction(QStringLiteral("按Enter键,发送消息"), this, SLOT(onEnterAction()));
    m_ctrlSendAction = menu->addAction(QStringLiteral("按Enter+Ctrl键,发送消息"), this, SLOT(onEnterCtrlAction()));
    
    QActionGroup* actiongroup = new QActionGroup(this);
    m_sendAction->setCheckable(true);
    m_ctrlSendAction->setCheckable(true);
    m_sendAction->setChecked(true);
    actiongroup->addAction(m_sendAction);
    actiongroup->addAction(m_ctrlSendAction);
    ui.sendBtn->setMenu(menu);
}

void TalkWindow::onEnterAction()
{
    m_sendAction->setChecked(true);

}

void TalkWindow::onEnterCtrlAction()
{
    m_ctrlSendAction->setChecked(true);
}
EmotionWindow.cpp
const int emotionColumn = 14;
const int emotionRow = std::ceil(170 / 14);

EmotionWindow::EmotionWindow(QWidget *parent)
    : QWidget(parent)
{
    setWindowFlags(Qt::FramelessWindowHint | Qt::SubWindow);
    setAttribute(Qt::WA_TranslucentBackground);
    setAttribute(Qt::WA_DeleteOnClose);

    ui.setupUi(this);
    initControl();
}

EmotionWindow::~EmotionWindow()
{

}

void EmotionWindow::initControl()
{
    CommonUtils::loadStyleSheet(this, "EmotionWindow");
    for (int row = 0; row < emotionRow; row++)
    {
        for (int column = 0; column < emotionColumn; column++)
        {
            EmotionLabelItem* label = new EmotionLabelItem(this);
            label->setEmotionName(row * emotionColumn + column);
            connect(label, &EmotionLabelItem::emotionClicked, this, &EmotionWindow::addEmotion);
            ui.gridLayout->addWidget(label, row, column);
        }
    }
}

void EmotionWindow::addEmotion(int emotionNum)
{
    hide();
    emit signalEmotionWindowHide();
    emit signalEmotionItemClicked(emotionNum);
}

void EmotionWindow::paintEvent(QPaintEvent *event)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    __super::paintEvent(event);
}

void EmotionWindow::showEvent(QShowEvent *event)
{
    setFocus();
    __super::showEvent(event);
}

void EmotionWindow::focusOutEvent(QFocusEvent *event)
{
    QWidget* widget = qApp->widgetAt(QCursor::pos());
    if (widget != this && widget != ui.emotionWidget && widget != ui.topWidget)
    {
        hide();
        emit signalEmotionWindowHide();
    }

    __super::focusOutEvent(event);
}
//QMsgTextEdit.cpp
QMsgTextEdit::QMsgTextEdit(QWidget *parent)
    : QTextEdit(parent)
{

}

QMsgTextEdit::~QMsgTextEdit()
{
    delteAllEmotionImage();
}

void QMsgTextEdit::delteAllEmotionImage()
{
    for (auto itor = m_emotionMap.constBegin(); itor != m_emotionMap.constEnd(); ++itor)
    {
        delete itor.key();
    }
    m_emotionMap.clear();
}

void QMsgTextEdit::addEmotionUrl(int emotionNum)
{
    const QString&& imageName = QString(":/TalkWindowShell/Resources/emotion/%1.png").arg(emotionNum);
    const QString&& flagName = QString("apng-%1-apng").arg(imageName);
    insertHtml(QString("").arg(flagName));
    if (m_listEmotionUrl.contains(imageName))
        return;
    else
        m_listEmotionUrl.append(imageName);

    QMovie* apngMovie = new QMovie(imageName, "apng", this);
    apngMovie->setCacheMode(QMovie::CacheNone);
    m_emotionMap.insert(apngMovie, flagName);

    connect(apngMovie, SIGNAL(frameChanged(int)), this, SLOT(onEmotionImageFrameChange(int)));
    apngMovie->start();
}

void QMsgTextEdit::onEmotionImageFrameChange(int frame)
{
    QMovie* movie = qobject_cast(sender());
    document()->addResource(QTextDocument::ImageResource, QUrl(m_emotionMap.value(movie)), movie->currentPixmap());
    setLineWrapColumnOrWidth(lineWrapColumnOrWidth());
}

你可能感兴趣的:(Qt模仿QQ聊天窗口界面(一))