第一步打开Qt Creator,点击新建NewProject Application –> Qt Widgets Application -> choose 创建项目名称例如: MyselfQQ,路径自己选择,注意不要有空格和中文 选择套件,点击下一步 选择基类QWidget,然后点击下一步
然后点击完成,至此项目创建完毕。
右击项目名,在弹出的快捷菜单中选择“添加新文件…”菜单项,在弹出的对话框中选择“Qt”选项。选择Qt设计师界面类,单击“Choose…”按钮;
界面模板选择Widget,点击下一步
类名填写 DialogList (可以起其他名称)点击下一步
在汇总中单击“完成”按钮,系统会为我们添加“dialoglist.h”头文件和“dialoglist.cpp”源文件以及dialoglist.ui设计文件
按照下图所示,设计对话框的UI,该窗口的大小为 250*700,其中的主要控件是QToolBox,修改该控件的currentItemText为“群成员”,QToolBox默认生成的第二页删除掉 在群成员里我们放入一个Widget做布局操作,可以先利用一些测试控件放入到其中,然后做垂直布局,然后把测试的控件删除掉,这时该Widget中就有了一个layout布局
测试,main函数中修改代码
运行项目,效果如图
向项目中导入资源,对应九个按钮需要九张图片作为头像图标使用,搜集九张图片(可用共享的资源或者自己收藏的图片,大小在80*80左右)
添加新文件 – Qt – Qt Resource 点击choose 名称 res 下一步,点击完成,生成res.qrc文件
右击res.qrc,点击open in Editor ,添加前缀 /
添加文件 – 将准备好的文件选中,点击打开,添加成功
在Drawer构造函数中加入如下代码
setWindowTitle(“Myself QQ 2017”);
设置主窗体标题图标
setWindowIcon(QPixmap(“:/images/qq.png”));
QVectorvToolBtn; //声明存放QtoolButton的容器 vToolBtn
for(int i = 0 ;i setText("斧头帮帮主"); //设置按钮名称
btn->setIcon(QPixmap(":/images/ftbz.png")); //设置图片
btn->setIconSize(QPixmap(":images/ftbz.png").size()); //设置图片大小
btn->setAutoRaise(true); //设置图片透明效果
btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);//设置按钮风格,同时显示文字和图标
ui->vLayout->addWidget(btn); //将按钮添加到布局中
vToolBtn.push_back(btn); //将9个按钮放入到布局中
}
运行效果如图:(有点辣眼睛。。。)
再次运行,效果如图
双击widget.ui文件进入设计模式,界面宽度属性分别设置为730和450,向界面中拖入部件并且进行设置,最终效果如图:
如上图中标注的1~8,下表中为上图的属性设置以及控件类型
其中前三个按钮 ,选中 checkable 属性; 其中所有的ToolBtn
属性中的toolTIp依次更改为 加粗、倾斜、下划线、更改字体颜色、保存聊天记录和 清空聊天记录
界面上 5号控件设置字体大小,设置区间为8~22(与腾讯QQ软件完全相同),双击该部件,点击 + 号按钮添加新项目如图: currentIndex属性设置为4,即默认为12号字
显示用户列表的TableWidget控件,将selectionModel属性选择为 SingleSelection(带有选中效果),将selectBehavior选择为 SelectRows(选中整行),取消选中的showGrid(表格显示)
双击TableWidget部件,添加“用户名”列,如图: 至此,所有弹出的聊天信息窗口全部设计完毕
下一步就是要关联起聊天的列表窗口和具体的聊天信息窗口了,也就是点击按钮弹出窗口。
//添加点击事件
for(int i = 0 ; i setWindowTitle(vToolBtn[i]->text());
chatWidget->setWindowIcon(vToolBtn[i]->icon());
chatWidget->show();
});
}
4.2 修改弹出框的构造函数
!!! Widget文件中的 构造改为explicit Widget(QWidget *parent ,QString usrname); 参数2 用于传入用户名,让具体的弹出框知道自己的用户名是什么
4.3 测试运行代码,点击窗口,弹出响应的对话框
4.4 解决一个窗口多次弹出的bug在dialogList.h中加入标示
QVectorisShow; 代表是否打开窗口的标识,false未打开,true打开
dialogList.cpp构造中 将9个标志位都置为false
//九个标识位设置
for(int i = 0 ; i widgetClose(); //发送关闭当前窗口的自定义信号
QWidget::closeEvent(e);
}
点击事件中再添加一行代码 测试,一个窗口不能多次弹出
widget中 定义枚举 enum MsgType {Msg,UsrEnter,UsrLeft} 分别代表 聊天信息、新用户加入、用户退出
5.1 声明聊天的方法widge.h中
public:
void sndMsg(MsgType type); //广播UDP消息
void usrEnter(QString username);//处理新用户加入
void usrLeft(QString usrname,QString time); //处理用户离开
QString getUsr(); //获取用户名
QString getMsg(); //获取聊天信息
private:
QUdpSocket * udpSocket; //udp套接字
qint16 port; //端口
QString uName; //用户名
void ReceiveMessage(); //接受UDP消息
5.2 widget.cpp中实现
构造函数中:
this->uName = usrname; //获取用户名
udpSocket = new QUdpSocket(this);
port = 23333;
udpSocket->bind(port,QUdpSocket::ShareAddress |QUdpSocket::ReuseAddressHint); //采用ShareAddress模式(即允许其它的服务连接到相同的地址和端口,特别是用在多客户端监听同一个服务器端口等时特别有效),和ReuseAddressHint模式(重新连接服务器)
connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::ReceiveMessage); 监听信号
sndMsg(UsrEnter);//有新用户加入
发送消息函数 sndMsg
void Widget::sndMsg(MsgType type)
{
QByteArray data;
QDataStream out(&data,QIODevice::WriteOnly);
out > msgType; //用户类型获取
QString usrName,msg; //用户名、信息
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
switch (msgType){
case Msg:
in >> usrName >>msg;
ui->msgBrowser->setTextColor(Qt::blue);
ui->msgBrowser->setCurrentFont(QFont("Times New Roman",12));
ui->msgBrowser->append("[ " + usrName + " ]" + time);
ui->msgBrowser->append(msg);
break;
case UsrEnter:
in >> usrName ;
usrEnter(usrName);
break;
case UsrLeft:
in >> usrName;
usrLeft(usrName,time);
break;
default:
break;
}
}
获取用户名
//获取用户名
QString Widget::getUsr()
{
return uName;
}
获取聊天信息
//获取聊天信息
QString Widget::getMsg()
{
QString msg = ui->msgTxtEdit->toHtml();
ui->msgTxtEdit->clear();
ui->msgTxtEdit->setFocus();
return msg;
}
新用户进入
//处理新用户加入
void Widget::usrEnter(QString usrname)
{
bool isEmpty = ui->usrTblWidget->findItems(usrname,Qt::MatchExactly).isEmpty();
if(isEmpty)
{
QTableWidgetItem *usr = new QTableWidgetItem(usrname);
ui->usrTblWidget->insertRow(0);
ui->usrTblWidget->setItem(0,0,usr);
ui->msgBrowser->setTextColor(Qt::gray);
ui->msgBrowser->setCurrentFont(QFont("Times New Roman",10));
ui->msgBrowser->append(tr("%1 在线!").arg(usrname));
ui->usrNumLbl->setText(tr("在线人数:%1").arg(ui->usrTblWidget->rowCount()));
//已经在线的各个端点也要告知新加入的端点他们自己的信息,若不这样做,在新端点用户列表中就无法显示其他已经在线的用户
sndMsg(UsrEnter);
}
}
用户离开
//用户离开
void Widget::usrLeft(QString usrname,QString time)
{
int rowNum = ui->usrTblWidget->findItems(usrname, Qt::MatchExactly).first()->row();
ui->usrTblWidget->removeRow(rowNum);
ui->msgBrowser->setTextColor(Qt::gray);
ui->msgBrowser->setCurrentFont(QFont("Times New Roman", 10));
ui->msgBrowser->append(QString("%1 于 %2 离开!").arg(usrname).arg(time));
ui->usrNumLbl->setText(QString("在线人数:%1").arg(ui->usrTblWidget->rowCount()));
}
重写离开Event void closeEvent(QCloseEvent *)
void Widget::closeEvent(QCloseEvent *e)
{
emit this->widgetClose();
sndMsg(UsrLeft);
udpSocket->close();
udpSocket->destroyed();
QWidget::closeEvent(e);
}
发送按钮和离开按钮信号槽连接
connect(ui->sendBtn,&QPushButton::clicked,this,[=](){
sndMsg(Msg);
});
connect(ui->exitBtn,&QPushButton::clicked,this,[=]()
{
this->close();
});
至此可以测试聊天功能
6. 辅助功能 6.1 字体设置connect(ui->fontCbx,&QFontComboBox::currentFontChanged,this,[=](const QFont &f){
ui->msgTxtEdit->setCurrentFont(f);
ui->msgTxtEdit->setFocus();
});
6.2 字号设置
void (QComboBox:: * cbxSingal)(const QString &text) = &QComboBox::currentIndexChanged;
connect(ui->sizeCbx,cbxSingal,this,[=](const QString &text){
ui->msgTxtEdit->setFontPointSize(text.toDouble());
ui->msgTxtEdit->setFocus();
});
6.3 加粗
connect(ui->boldTBtn,&QToolButton::clicked,this,[=](bool checked){
if(checked)
{
ui->msgTxtEdit->setFontWeight(QFont::Bold);
}
else
{
ui->msgTxtEdit->setFontWeight(QFont::Normal);
}
ui->msgTxtEdit->setFocus();
});
6.4 倾斜
connect(ui->italicTBtn,&QToolButton::clicked,this,[=](bool checked){
ui->msgTxtEdit->setFontItalic(checked);
ui->msgTxtEdit->setFocus();
});
6.5下划线
connect(ui->underlineTBtn,&QToolButton::clicked,this,[=](bool checked){
ui->msgTxtEdit->setFontUnderline(checked);
ui->msgTxtEdit->setFocus();
});
6.6 设置文本颜色
connect(ui->colorTBtn,&QToolButton::clicked,this,[=](){
color = QColorDialog::getColor(color,this); //color对象可以在widget.h中定义私有成员
if(color.isValid())
{
ui->msgTxtEdit->setTextColor(color);
ui->msgTxtEdit->setFocus();
}
});
6.7 保存聊天记录
connect(ui->saveBtn,&QToolButton::clicked,this,[=](){
if(ui->msgBrowser->document()->isEmpty())
{
QMessageBox::warning(this,"警告","聊天记录为空,无法保存!",QMessageBox::Ok);
}
else
{
QString fName = QFileDialog::getSaveFileName(this,"保存聊天记录","聊天记录","(*.txt)");
if(!fName.isEmpty())
{
//保存名称不为空再做保存操作
QFile file(fName);
file.open(QIODevice::WriteOnly | QFile::Text);
QTextStream stream(&file);
stream toPlainText();
file.close();
}
}
});
6.8 清空聊天记录
connect(ui->clearTBtn,&QToolButton::clicked,[=](){
ui->msgBrowser->clear();
});
至此本案例全部完成!