Qt项目-----简易QQ(超详细,适合小白)
创建新项目新建项目,以Qt Widgets Application为模板选择QWidget为基类建立完成后,项目视图如下所示:创建对话框列表添加对话框列表然后右击MyQQ,选择添加新文件选择Qt->Qt设计师界面类,选择Widget为新类命名为DialogList建立完成后,项目视图如下所示(红框内为新添加文件):在dialoglist.ui中修改DialogList对象的宽度为250,高度
创建新项目
新建项目,以Qt Widgets Application为模板


选择QWidget为基类

建立完成后,项目视图如下所示:

注意:建立好项目后,可以先编译运行下,确定建立的项目没有问题。
创建对话框列表
添加对话框列表
然后右击MyQQ,选择添加新文件

选择Qt->Qt设计师界面类,选择Widget

为新类命名为DialogList

建立完成后,项目视图如下所示(红框内为新添加文件):

设计对话框列表
在dialoglist.ui中修改DialogList对象的宽度为250,高度为700

拖拽QToolBox到DialogList中,删除页2(选中ToolBox对象,右键选择2的页2->删除页),对DialogList进行垂直布局,,修改QToolBox的currentItemText为群成员,修改DialogList的布局边缘为0

为QToolBox添加控件,进行垂直布局,然后删除控件,从而为page添加布局(之前page没有布局选项),修改page的布局名称为vLayout


导入资源
为Qt添加资源文件,右击项目名称MyQQ,选择Qt->Qt Resource File,下一步命名为res

确定后,项目视图如下:

添加前缀和文件,导入图片
main.cpp进行修改如下(让DialogList进行显示):
#include "widget.h"
#include <QApplication>
#include<dialoglist.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Widget w;
// w.show();
DialogList list;
list.show();
return a.exec();
}
dialoglist.cpp修改如下:
#include "dialoglist.h"
#include "ui_dialoglist.h"
DialogList::DialogList(QWidget *parent) :
QWidget(parent),
ui(new Ui::DialogList)
{
ui->setupUi(this);
//设置标题
setWindowTitle("MyQQ");
//设置图标
setWindowIcon(QPixmap(":/resource/1.jpg"));
}
DialogList::~DialogList()
{
delete ui;
}
运行程序,显示如下:

对各个成员用toolbutton按钮进行设置,(修改dialoglist.cpp)代码如下:
#include<QToolButton>
//人物名称
QStringList nameList;
nameList<<"悟空"<<"唐僧"<<"八戒"<<"沙僧"<<"至尊宝"<<
"紫霞"<<"白骨精"<<"蜘蛛精"<<"牛魔王"<<"铁扇公主";
//人物头像
QList<QString> iconList;
iconList<<"wukong.jpg"<<"tangsengt.jpg"<<"bajie.jpg"<<"shaseng.jpg"<<"zhizunbao.jpg"<<
"zixia.jpg"<<"baigujing.jpg"<<"zhizhujing.jpg"<<"niumowang.jpg"<<"tieshangongzhu.jpg";
//将10个人物用QVector进行维护
QVector<QToolButton*> vToolbtn;
for(int i=0;i<10;i++)
{
//设置列表成员
QToolButton* btn = new QToolButton;
//设置文字
btn->setText(nameList[i]);
//设置头像
QString str = QString(":/source/%1").arg(iconList.at(i));
btn->setIcon(QIcon(str));
//设置头像大小
btn->setIconSize(QSize(100,100));
//设置按钮风格 透明
btn->setAutoRaise(true);
//设置文字和图片一起显示
btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
//加到垂直布局中
ui->vLayout->addWidget(btn);
vToolbtn.push_back(btn);
}
设置完成后,运行效果如下:

聊天窗口搭建
对widget.uii进行设置如下:
- 调整widget大小
- 把text browser 控件拖进widget,并做水平布局,调整布局边缘为0

- 把6个toolbutton,QfontComBox,ComBox拖进Widget中,并做水平布局,将Widget变型为QFrame,设置frameshape为Box
- 把text edit拖进widget,调整边缘为0
- 将上述三个控件拖进新的widget中,并做垂直布局,变形为QFrame,调整边缘为0
经过上述操作后,得到界面如下所示:

调整text edit所在控件最大高度为100,使界面更为美观
- 把table widget拖进新的widget中,再对它与上述窗口在新的widget中进行水平布局,调整table widget所属控件的最大宽度为180
布局完成后,界面如下:

- 把两个pushbutton和一个label拖进一个widget中,将新的widget进行布局(加水平弹簧horizontal spacer)及边缘调整后与上述窗口在新的widget中进行垂直布局及边缘调整
经过上述操作后,得到如下界面

调整Widget大小为730*450
双击组合框,点“+”对组合框进行编辑

对currentIndex进行设置可以修改默认值

为字体选项进行如下设置(前三个选项选中checkable进行是否选中的显示,tooltip加上相应文字用来鼠标靠近时提示),设置toolbutton大小为32*32,iconsize大小为26*26

设置tablewidget属性
为table widget添加用户名的列

selectionMode选择SingleSelection,selectBehaviors选择selectRows
对控件名称根据功能进行设置
设置聊天窗口
widget.h中修改widget的构造函数
explicit Widget(QWidget *parent,QString name);
/*
原函数为
explicit Widget(QWidget *parent=0);
*/
widget.cpp中进行相应修改
Widget::Widget(QWidget *parent,QString name) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
/*
原函数为
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
*/
dialoglist.cpp中增加信号槽,点击群成员头像出现相应用户对话框
#include"widget.h"
//对9个按钮添加信号槽
for(int i=0;i<10;i++)
{
connect(vToolbtn[i],&QToolButton::clicked,[=](){
//弹出聊天对话框
Widget* widget = new Widget(0,vToolbtn[i]->text());
//设置窗口标题
widget->setWindowTitle(vToolbtn[i]->text());
//设置窗口头像
widget->setWindowIcon(vToolbtn[i]->icon());
//窗口进行显示
widget->show();
});
如果已经打开相应人物聊天窗口,就不要再次打开
dialoglist.h中定义bool类型变量容器,用来记录相应人物窗口是否被打开
QVector<bool> isShow;
widget.h中定义窗口关闭信号和事件
signals:
//关闭窗口发送关闭信息
void closeWidget();
public:
//关闭窗口会触发关闭事件
void closeEvent(QCloseEvent *);
widget.cpp中对关闭事件进行实现
void Widget::closeEvent(QCloseEvent *event)
{
emit this->closeWidget();
}
在dialoglist.cpp中对打开和关闭窗口状态进行记录,已经打开窗口则进行警告
#include<QToolButton>
#include"widget.h"
#include<QMessageBox>
DialogList::DialogList(QWidget *parent) :
QWidget(parent),
ui(new Ui::DialogList)
{
ui->setupUi(this);
//设置标题
setWindowTitle("MyQQ");
//设置图标
setWindowIcon(QIcon(":/source/journeytowest.jpg"));
//人物名称
QStringList nameList;
nameList<<"悟空"<<"唐僧"<<"八戒"<<"沙僧"<<"至尊宝"<<
"紫霞"<<"白骨精"<<"蜘蛛精"<<"牛魔王"<<"铁扇公主";
//人物头像
QList<QString> iconList;
iconList<<"wukong.jpg"<<"tangsengt.jpg"<<"bajie.jpg"<<"shaseng.jpg"<<"zhizunbao.jpg"<<
"zixia.jpg"<<"baigujing.jpg"<<"zhizhujing.jpg"<<"niumowang.jpg"<<"tieshangongzhu.jpg";
//将10个人物用QVector进行维护
QVector<QToolButton*> vToolbtn;
for(int i=0;i<10;i++)
{
//设置列表成员
QToolButton* btn = new QToolButton;
//设置文字
btn->setText(nameList[i]);
//设置头像
QString str = QString(":/source/%1").arg(iconList.at(i));
btn->setIcon(QIcon(str));
//设置头像大小
btn->setIconSize(QSize(100,100));
//设置按钮风格 透明
btn->setAutoRaise(true);
//设置文字和图片一起显示
btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
//加到垂直布局中
ui->vLayout->addWidget(btn);
vToolbtn.push_back(btn);
isShow.push_back(false);
}
//对9个按钮 添加信号槽
for(int i=0;i<vToolbtn.size();i++)
{
connect(vToolbtn[i],&QToolButton::clicked,[=](){
//如果被打开了,就不要再次打开
if(isShow[i])
{
QString str = QString("%1窗口已经被打开了").arg(vToolbtn[i]->text());
QMessageBox::warning(this,"警告",str);
return;
}
isShow[i] = true;
//弹出聊天对话框
//构造聊天窗口,对窗口名称和头像进行初始化
//参数1 顶层方式弹出(关闭dialoglist控件窗口,widget窗口不会关闭) 参数2 窗口名字
Widget* widget = new Widget(0,vToolbtn[i]->text());
//设置窗口标题
widget->setWindowTitle(vToolbtn[i]->text());
//设置窗口头像
widget->setWindowIcon(vToolbtn[i]->icon());
//进行显示
widget->show();
//关闭窗口时调整状态为false
connect(widget,&Widget::closeWidget,[=](){
isShow[i] = false;
});
});
}
}
实现基本聊天功能
widget.h中定义枚举enum MsgType{Msg,UsrEnter,UsrLeft},分别代表聊天信息,新用户加入,用户退出
private:
enum MsgType{Msg,UsrEnter,usrLeft};
声明聊天的方法
MyQQ.pro文件中添加network模块
QT += network
widget.h中
#include<QUdpSocket>
public:
void sndMsg(MsgType type);//广播UDP消息
void usrEnter(QString username);//处理新用户加入
void usrLeft(QString usrname,QString time);//处理用户离开
QString getUsr();//获取用户名
QString getMsg();//获取聊天信息
private:
QUdpSocket* udpsocket;//udp套接字
qint64 port; //端口
QString uName;//用户名
void ReceiveMessage();//接收UDP消息
widget.cpp中实现发送接收消息
#include<QDataStream>
#include<QMessageBox>
#include<QDateTime>
//初始化操作
udpsocket = new QUdpSocket(this);
//用户名获取
uName = name;
//端口号
this->port = 9999;
//绑定端口号
//QUdpSocket::ShareAddress为共享地址,QUdpSocket::ReuseAddressHint为断线重连
udpsocket->bind(this->port,QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint);
//发送新用户进入
//sndMsg(UsrEnter);
//点击发送按钮,发送消息
connect(ui->sendBtn,&QPushButton::clicked,[=](){
sndMsg(Msg);
});
//监听别人发送的消息
connect(udpsocket,&QUdpSocket::readyRead,this,&Widget::ReceiveMessage);
//接收UDP消息
void Widget::ReceiveMessage()
{
//获取报文长度
qint64 size = udpsocket->pendingDatagramSize();
QByteArray array = QByteArray(size,0);
//将数据读取到array中
udpsocket->readDatagram(array.data(),size);
//解析数据
//第一段 类型 第二段 用户名 第三段 内容
QDataStream stream(&array,QIODevice::ReadOnly);
int msgType;
QString usrName;
QString msg;
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
stream>>msgType;
switch (msgType) {
case Msg:
stream>>usrName>>msg;
//追加聊天记录
//设置颜色
ui->msgBrowser->setTextColor(Qt::blue);
ui->msgBrowser->append("["+usrName+"]"+time);
ui->msgBrowser->append(msg);
break;
case UsrEnter:
break;
case UsrLeft:
break;
default:
break;
}
}
void Widget::sndMsg(MsgType type)//广播UDP消息
{
//发送消息分为3类
//发送的数据做分段处理 第一段 类型 第二段 用户名 第三段 具体内容
QByteArray array;
//将数据写入array中
QDataStream stream(&array,QIODevice::WriteOnly);
//进行数据拼接
stream<<type<<getUsr(); //第一段内容,添加到流中 第二段 用户名
switch(type)
{
case Msg://普通消息发送
//判断如果用户没有输入内容,不发任何消息
if(ui->msgTxtEdit->toPlainText()=="")
{
QMessageBox::warning(this,"警告","发送内容不能为空");
return;
}
//第三段 发送的具体内容
stream<<getMsg();
break;
case UsrEnter://新用户进入消息
break;
case UsrLeft://用户离开消息
break;
default:
break;
}
//书写报文
//QHostAddress::Broadcast等价于QHostAddress(255.255.255.255),意为广播发送
udpsocket->writeDatagram(array,QHostAddress::Broadcast,port);
}
QString Widget::getUsr()//获取用户名
{
return this->uName;
}
QString Widget::getMsg()//获取聊天信息
{
QString str = ui->msgTxtEdit->toHtml();
//清空输入框
ui->msgTxtEdit->clear();
//光标返回原处
ui->msgTxtEdit->setFocus();
return str;
}
新用户进入:
void Widget::usrEnter(QString username)//处理新用户加入
{
//更新右侧Table Widget
bool isEmpty = ui->usrTblWidget->findItems(username,Qt::MatchExactly).isEmpty();
if(isEmpty)
{
QTableWidgetItem* usr = new QTableWidgetItem(username);
//插入行
ui->usrTblWidget->insertRow(0);
ui->usrTblWidget->setItem(0,0,usr);
//追加聊天记录
ui->msgBrowser->setTextColor(Qt::gray);
ui->msgBrowser->append(QString("%1 上线了").arg(username));
//在线人数更新
ui->usrNumLbl->setText(QString("在线用户 :%1 人").arg(ui->usrTblWidget->rowCount()));
//把自身信息广播出去
sndMsg(UsrEnter);
}
}
用户离开:
void Widget::usrLeft(QString usrname,QString time)//处理用户离开
{
bool isEmpty = ui->usrTblWidget->findItems(usrname,Qt::MatchExactly).isEmpty();
if(!isEmpty)
{
int row = ui->usrTblWidget->findItems(usrname,Qt::MatchExactly).first()->row();
ui->usrTblWidget->removeRow(row);
//追加聊天信息
ui->msgBrowser->setTextColor(Qt::gray);
ui->msgBrowser->append(QString("%1于%2离开").arg(usrname).arg(time));
//更新在线人数
ui->usrNumLbl->setText(QString("在线用户 :%1 人").arg(ui->usrTblWidget->rowCount()));
}
}
对关闭窗口事件做更新:
void Widget::closeEvent(QCloseEvent *event)
{
emit this->closeWidget();
sndMsg(UsrLeft);
//断开套接字
udpsocket->close();
udpsocket->destroyed();
//如果有别的事,让父类接着处理
QWidget::closeEvent(event);
}
辅助功能设置:
#include<QColorDialog>
#include<QFileDialog>
#include<QFile>
#include<QTextStream>
/*******************************辅助功能设置**************************/
//设置字体
connect(ui->fontCbx,&QFontComboBox::currentFontChanged,[=](const QFont &f){
ui->msgTxtEdit->setCurrentFont(f);
ui->msgTxtEdit->setFocus();
});
//字号
//发生函数重载,因此需要函数指针表明具体调用函数
void (QComboBox:: *cbxsignal)(const QString &text) = &QComboBox::currentIndexChanged;
connect(ui->sizeCbx,cbxsignal,[=](const QString &text){
ui->msgTxtEdit->setFontPointSize(text.toDouble());
ui->msgTxtEdit->setFocus();
});
//加粗
connect(ui->boldTBtn,&QToolButton::clicked,[=](bool isBold){
if(isBold)
{
ui->msgTxtEdit->setFontWeight(QFont::Bold);
}
else
{
ui->msgTxtEdit->setFontWeight(QFont::Normal);
}
});
//倾斜
connect(ui->italicTBtn,&QToolButton::clicked,[=](bool isItalic){
if(isItalic)
{
ui->msgBrowser->setFontItalic(true);
}
else
{
ui->msgBrowser->setFontItalic(false);
}
});
//下划线
connect(ui->underlineTBtn,&QToolButton::clicked,[=](bool isUnderline){
if(isUnderline)
{
ui->msgTxtEdit->setFontUnderline(true);
}
else
{
ui->msgTxtEdit->setFontUnderline(false);
}
});
//字体颜色
connect(ui->colorTBtn,&QToolButton::clicked,[=](){
QColor color = QColorDialog::getColor(Qt::red);
ui->msgTxtEdit->setTextColor(color);
});
//清空聊天记录
connect(ui->clearTBtn,&QToolButton::clicked,[=](){
ui->msgBrowser->clear();
});
//保存聊天记录
connect(ui->saveTBtn,&QToolButton::clicked,[=](){
if(ui->msgBrowser->document()->isEmpty())
{
QMessageBox::warning(this,"警告","内容不能为空");
return;
}
else
{
QString path = QFileDialog::getSaveFileName(this,"保存记录","聊天记录","(*.txt)");
if(path.isEmpty())
{
QMessageBox::warning(this,"警告","路径不能为空");
return;
}
else
{
QFile file(path);
//打开模式加换行操作
file.open(QIODevice::WriteOnly|QIODevice::Text);
QTextStream stream(&file);
stream<<ui->msgBrowser->toPlainText();
file.close();
}
}
});
运行结果如下:

更多推荐


所有评论(0)