您当前的位置: 首页 >  qt

34 QT - 聊天案例

杨林伟 发布时间:2019-10-18 16:51:46 ,浏览量:2

1. 新建项目 1.1 创建新项目

第一步打开Qt Creator,点击新建NewProject Application –> Qt Widgets Application -> choose 创建项目名称例如: MyselfQQ,路径自己选择,注意不要有空格和中文 在这里插入图片描述 选择套件,点击下一步 选择基类QWidget,然后点击下一步 在这里插入图片描述 然后点击完成,至此项目创建完毕。

2. 创建对话列表 2.1 添加新文件,对话列表类DialogList

右击项目名,在弹出的快捷菜单中选择“添加新文件…”菜单项,在弹出的对话框中选择“Qt”选项。选择Qt设计师界面类,单击“Choose…”按钮;

界面模板选择Widget,点击下一步

类名填写 DialogList (可以起其他名称)点击下一步

在汇总中单击“完成”按钮,系统会为我们添加“dialoglist.h”头文件和“dialoglist.cpp”源文件以及dialoglist.ui设计文件 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

2.2 设计对话框列表UI

按照下图所示,设计对话框的UI,该窗口的大小为 250*700,其中的主要控件是QToolBox,修改该控件的currentItemText为“群成员”,QToolBox默认生成的第二页删除掉 在这里插入图片描述 在群成员里我们放入一个Widget做布局操作,可以先利用一些测试控件放入到其中,然后做垂直布局,然后把测试的控件删除掉,这时该Widget中就有了一个layout布局 在这里插入图片描述 测试,main函数中修改代码 在这里插入图片描述 运行项目,效果如图 在这里插入图片描述

2.3 资源导入

向项目中导入资源,对应九个按钮需要九张图片作为头像图标使用,搜集九张图片(可用共享的资源或者自己收藏的图片,大小在80*80左右)

添加新文件 – Qt – Qt Resource 点击choose 名称 res 下一步,点击完成,生成res.qrc文件 在这里插入图片描述 在这里插入图片描述

右击res.qrc,点击open in Editor ,添加前缀 / 在这里插入图片描述 在这里插入图片描述 添加文件 – 将准备好的文件选中,点击打开,添加成功 在这里插入图片描述

2.4 设置窗体标题和图标 2.4.1设置标题

在Drawer构造函数中加入如下代码

setWindowTitle(“Myself QQ 2017”);

在这里插入图片描述

2.4.2 设置图标

设置主窗体标题图标

setWindowIcon(QPixmap(“:/images/qq.png”));

在这里插入图片描述

2.5设置列表中的按钮 2.5.1 创建9个按钮存放到QVector容器中
  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个按钮放入到布局中
  }

运行效果如图:(有点辣眼睛。。。) 在这里插入图片描述

2.5.2 替换图片,改为不同的资源

在这里插入图片描述 再次运行,效果如图 在这里插入图片描述

3. 设计聊天窗口 3.1 界面

双击widget.ui文件进入设计模式,界面宽度属性分别设置为730和450,向界面中拖入部件并且进行设置,最终效果如图: 在这里插入图片描述

3.2 控件类型和属性设置 3.2.1 各个控件设置

如上图中标注的1~8,下表中为上图的属性设置以及控件类型 在这里插入图片描述

3.2.2 ToolBtn详细设置

其中前三个按钮在这里插入图片描述 ,选中 checkable 属性; 其中所有的ToolBtn在这里插入图片描述属性中的toolTIp依次更改为 加粗、倾斜、下划线、更改字体颜色、保存聊天记录和 清空聊天记录

3.2.3字体大小下拉框设置

界面上 5号控件设置字体大小,设置区间为8~22(与腾讯QQ软件完全相同),双击该部件,点击 + 号按钮添加新项目如图: 在这里插入图片描述 currentIndex属性设置为4,即默认为12号字

3.2.4 TableWidget设置

显示用户列表的TableWidget控件,将selectionModel属性选择为 SingleSelection(带有选中效果),将selectBehavior选择为 SelectRows(选中整行),取消选中的showGrid(表格显示)

双击TableWidget部件,添加“用户名”列,如图: 在这里插入图片描述 至此,所有弹出的聊天信息窗口全部设计完毕

4 关联图片按钮与聊天窗口 4.1 添加按钮点击事件

下一步就是要关联起聊天的列表窗口和具体的聊天信息窗口了,也就是点击按钮弹出窗口。

   //添加点击事件
    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);
}

点击事件中再添加一行代码 在这里插入图片描述 测试,一个窗口不能多次弹出

5. 实现基本聊天功能

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();
});

至此本案例全部完成!

关注
打赏
1688896170
查看更多评论

杨林伟

暂无认证

  • 2浏览

    0关注

    3183博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.1510s