创建新项目

新建项目,以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();
            }
        }

    });

运行结果如下:

 

 

 

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐