简述
最近利用业余时间,模仿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());
}