基於C++/qml的聊天小軟件(含源碼)

 

Server源碼

 

main.qml

import  QtQuick 2.4
import QtQuick.Window 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import Server_support 1.0
Window{


    id:window
    width:800
    height:550

    Rectangle{
        width:800
        height:550
        gradient: Gradient { //漸變屬性
            GradientStop{//從上到下顏色漸變,需要從做到右使用屬性rotation設置90即可
                position: 0.0; color: "white"
            }
            GradientStop{
                position: 1.0; color: "pink"
            }
        }
    }
    visible:true
    ListView{
        add: Transition {
            //設置增加Item時的動畫 from 100,100  to不設置 就是默認在ListView
            NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
        }
        id:listview
        anchors.top: parent.top
        anchors.bottom: bottomrect.top
        anchors.left:parent.left
        anchors.right:parent.right
        //anchors的對象要麼是兄弟結點(提供id)
        //要麼就是子節點(parent)
        delegate:Component{ //這裏delegate:後面必須是Component
            Rectangle{
                width:550
                height:label1.height+20
                opacity: 0.8
                // color:"black"
                BorderImage{
                    //聊天氣泡
                    id:qipao
                    source:"pao.png"
                    width:label1.width+30
                    height:label1.height<=30?30:label1.height+5
                    //  width:20
                    border.left: 10
                    border.right: 10
                    border.top:10
                    border.bottom:10
                    x:parent.width-width
                    Text{
                        id:label1
                        /*************
                                             此處爲可變大小的聊天氣泡的重點
                                             根據獲取值的長度 和每個字佔的像素
                                            *************/
                        width:label1.text.length<=10?label1.text.length*12:120
                        font.pixelSize: 12
                        anchors.centerIn:parent
                        anchors.leftMargin:10
                        wrapMode: Text.Wrap //多行文本 超過width就自動換行
                        text:detail
                    }
                }
            }
        }
        model:ListModel{
            id:listmodel
            ListElement{
                detail:"This is Server."

            }
        }
    }
    //右側
    Rectangle {
        id:message3

        border.color: "black"
        anchors.right: parent.right
        anchors.top: window.top
        height:510
        width:window.width*0.3
        gradient: Gradient { //漸變屬性
            GradientStop{//從上到下顏色漸變,需要從做到右使用屬性rotation設置90即可
                position: 0.0; color: "red"
            }
            GradientStop{
                position: 1.0; color: "blue"
            }
        }
    }

    Label{
        id:label2;
        text:"value";
        anchors.top: message3.top
        x:570
    }
    //底部
    Rectangle{
        height: 40
        width: 550
        anchors.bottom: parent.bottom
        id:bottomrect
        Row{
            TextField{
                id:textfield
                placeholderText: "輸入內容"
                height:bottomrect.height
                width:window.width*0.7
            }
        }

       Button{
            id:button1
            text:"Send"
            x:560
            anchors.top: message3.bottom
            onClicked: {

                listmodel.append({"detail":textfield.text})
                var result = textfield.text
                server.sendMessage(result);
                //textfield.text='' 發送消息後清空輸入框
            }
        }
        Button
        {
            id:button2
            text:"Connect"
            anchors.left: button1.right
            onClicked:
            {
                label2.text=server.mystring
                server.connect_client();
            }
            //連接信號 到qml
            Connections{
                target:server;
                onMystringChanged:label2.text = str;
            }
        }
        Button
        {
            id:button3
            text:"Quit"
            anchors.left: button2.right
            onClicked:
            {
                window.close();
            }
        }
    }
    Server
    {
        id:server
    }
    //左側接受消息
    //    Label{
    //        id:recv_message_window;
    //        text:"recv_message";
    //        width:275
    //        height:550
    //        y:20
    //       Button
    //       {
    //           id:button4
    //           text:"recvmsg"
    //           x:750
    //           y:490

    //           //anchors.right: window.right
    //           onClicked:
    //           {
    //               recv_message_window.text=server.message
    //           }
    //           Connections{
    //                target:server;
    //                onMessageChanged: recv_message_window.text = str;
    //                      }
    //        }
    //    }
    ListView{
        width:200
        height:550
        add: Transition {
            //設置增加Item時的動畫 from 100,100  to不設置 就是默認在ListView
            NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
        }
        id:listview2
        anchors.top: parent.top
        anchors.bottom: bottomrect.top
        anchors.left:parent.left
        anchors.right:parent.right
        //anchors的對象要麼是兄弟結點(提供id)
        //要麼就是子節點(parent)
        delegate:Component{ //這裏delegate:後面必須是Component
            Rectangle{
                width:200
                height:label3.height
                opacity: 0.8
                BorderImage{
                    //聊天氣泡
                    id:qipao
                    source:"pao.png"
                    width:label3.width+30
                    height:label3.height<=30?30:label3.height+5
                    //  width:20
                    border.left: 10
                    border.right: 10
                    border.top:10
                    border.bottom:10
                    x:parent.width-width
                    Text{
                        id:label3
                        /*************
                         此處爲可變大小的聊天氣泡的重點
                         根據獲取值的長度和每個字佔的像素
                         *************/
                        width:label3.text.length<=10?label3.text.length*12:120
                        font.pixelSize: 12
                        anchors.centerIn:parent
                        anchors.leftMargin:10
                        wrapMode: Text.Wrap //多行文本 超過width就自動換行
                        text:detail
                    }
                }
            }
        }
        model:ListModel{
            id:listmodel2
            ListElement{
                detail:""
            }
        }
    }
    Rectangle{
        anchors.top: parent.top
        id:bottomrect2
        Row{
            Text{
                id:textfield2
                height:bottomrect2.height
                width:window.width*0.7
               // anchors.top : ListView.top
            }
        }
    }
    Button
    {
        id:button4
        text:"recvmsg"
        x:720
        y:510
        anchors.left: button3.right
        onClicked:
        {
            listmodel2.append({"detail":textfield2.text})
            textfield2.text=server.message
        }
        Connections{
            target:server;
            onMessageChanged: textfield2.text = str;
        }
    }
}

server.cpp

#include "server.h"
static SOCKET slisten;
static SOCKET sClient;
Server::Server(QObject *parent):QObject(parent)
{
    m_pstring = new QString;
    recv_data = new QString;
    send_data = new QString;
}
Server::~Server()
{
    delete this->m_pstring;
}


QString Server::getString()
{
    setString("waiting connect...");
    return *(this->m_pstring);
}


void Server::setString(QString string){
    *(this->m_pstring)=string;
    emit mystringChanged(string);//發送信號
}


QString Server::message()
{
    return *recv_data;
}
void Server::setMessage(QString string)
{
    *recv_data=string;
}
void Server::sendMessage(QString string)
{
    *send_data = string;
    qDebug()<<*send_data;
}


void Server::connect_client()
{
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    if (WSAStartup(sockVersion, &wsaData) != 0)
    {
        exit(0);
    }
    slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (slisten == INVALID_SOCKET)
    {
        cout<<"socket error !"<<endl;
        exit(0);
    }
    else
        cout<<"socket suceess."<<endl;
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8080);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    if (::bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        cout <<  "bind error !" << endl;
    }
    else
        cout<<"bind success."<<endl;
    if (listen(slisten, 5) == SOCKET_ERROR)
    {
        cout << "listen error !"<< endl;
        exit(0);
    }
    else
        cout<<"listen succeed."<<endl;

    start_thread1();
}



void Server::recvsend_message()
{
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);
    int  count=0;
    start_thread2();

    while(true)
    {
        count++;
        if(count==1)
        {
            cout<<"wating connect..."<<endl;
        }
        sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
        if(count==1)
        {
            cout<<"accept one client."<<endl;
        }
        if (sClient == INVALID_SOCKET)
        {
            printf("accept error !");
            continue;
        }
        if(count == 1)
        {
            cout <<"accepted a connection:"<< inet_ntoa(remoteAddr.sin_addr) << endl;
        }
        cout << inet_ntoa(remoteAddr.sin_addr)<<":";
        send_news();

    }
    closesocket(sClient);
    WSACleanup();
}


void Server::recv_news()
{
    char revData[255];
    int ret = 0;
    int count = 0;
    while(true)
    {
        ret = recv(sClient, revData, 255, 0);
        count++;
        if(count == 1)
        {
            cout<<"recv success!"<<endl;
        }
        if (ret > 0)
        {
            revData[ret] = '\0';
            *recv_data = QString(QLatin1String(revData));
            qDebug()<<*recv_data;
            emit messageChanged(*recv_data);
            cout<<"recv a massgae:"<<revData<<endl;
        }
    }
}
void Server::send_news()
{

    char sendbuffer[255];
    while(true)
    {
        if((*send_data).size() > 0)
        {
            QByteArray buffer = (*send_data).toUtf8();
            char *sendData = buffer.data();

            strcpy(sendbuffer,sendData);
            sendbuffer[strlen(sendbuffer)]='\0';
            cout<<sendbuffer<<endl;
            send(sClient, sendbuffer, strlen(sendbuffer), 0);
            *send_data = "\0";
            memset(sendbuffer,0,255);
        }
    }
}



void Server::start_thread1()
{
    std::thread t1(&Server::thread1,this);
    t1.detach();
}
void* Server::thread1(void *this_)
{
    Server *_this = (Server*) this_;
    _this->recvsend_message();
    return _this;
}

void Server::start_thread2()
{
    std::thread t2(&Server::thread2,this);
    t2.detach();
}

void* Server::thread2(void *this_)
{
    Server *_this = (Server*) this_;
    _this->recv_news();
    return _this;
}




void Server::start_thread3()
{
    std::thread t3(&Server::thread3,this);
    t3.detach();
}
void* Server::thread3(void *this_)
{
    Server *_this = (Server*) this_;
    _this->send_news();
    return _this;
}

server.h

#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include<QString>
#include<qdebug.h>
#include<iostream>
#include<windows.h>
#include<thread>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
class Server : public QObject
{
    Q_OBJECT
    //暴露給QML 屬性
    Q_PROPERTY(QString mystring READ getString WRITE setString NOTIFY mystringChanged)
    Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged)
public:
    explicit Server(QObject *parent = 0);
    Q_INVOKABLE QString getString(); //Q_INVOCABLE暴露給 QML
    Q_INVOKABLE void setString(QString string);
    Q_INVOKABLE QString message();

    Q_INVOKABLE void setMessage(QString string);
    Q_INVOKABLE void sendMessage(QString string);

    ~Server();
    Q_INVOKABLE void connect_client();
    void recvsend_message();
    void recv_news();
    void send_news();
    void start_thread1();
    void start_thread2();
    void start_thread3();
    static void* thread1(void* this_);
    static void* thread2(void* this_);
    static void* thread3(void* this_);
signals:
    void  mystringChanged(QString value); //信號
    void  messageChanged(QString str);
public:
    QString *m_pstring;
    QString *recv_data;
    QString *send_data;
};
#endif // SERVER_H

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include<QtQml>
#include"server.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    //註冊到QML
    qmlRegisterType<Server>("Server_support",1,0,"Server");
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

 

客戶端源碼

main.qml

import  QtQuick 2.4
import QtQuick.Window 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import RegisterClient 1.0
Window{
    id:window

    width:800
    height:550

    Rectangle{
        width:800
        height:550
        gradient: Gradient { //漸變屬性
            GradientStop{//從上到下顏色漸變,需要從做到右使用屬性rotation設置90即可
                position: 0.0; color: "white"
            }
            GradientStop{
                position: 1.0; color: "pink"
            }
        }
    }
    visible:true
    ListView{
        add: Transition {
            //設置增加Item時的動畫 from 100,100  to不設置 就是默認在ListView
            NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
        }
        id:listview
        anchors.top: parent.top
        anchors.bottom: bottomrect.top
        anchors.left:parent.left
        anchors.right:parent.right
        //anchors的對象要麼是兄弟結點(提供id)
        //要麼就是子節點(parent)
        delegate:Component{ //這裏delegate:後面必須是Component
            Rectangle{
                width:550
                height:label1.height+20
                opacity: 0.8
                // color:"black"
                BorderImage{
                    //聊天氣泡
                    id:qipao
                    source:"pao.png"
                    width:label1.width+30
                    height:label1.height<=30?30:label1.height+5
                    //  width:20
                    border.left: 10
                    border.right: 10
                    border.top:10
                    border.bottom:10
                    x:parent.width-width
                    Text{
                        id:label1
                        /*************
                                             此處爲可變大小的聊天氣泡的重點
                                             根據獲取值的長度 和每個字佔的像素
                                            *************/
                        width:label1.text.length<=10?label1.text.length*12:120
                        font.pixelSize: 12
                        anchors.centerIn:parent
                        anchors.leftMargin:10
                        wrapMode: Text.Wrap //多行文本 超過width就自動換行
                        text:detail
                    }
                }
            }
        }
        model:ListModel{
            id:listmodel
            ListElement{
                detail:"This is Client."

            }
        }
    }
    //右側
    Rectangle {
        id:message3

        border.color: "black"
        anchors.right: parent.right
        anchors.top: window.top
        height:510
        width:window.width*0.3
        gradient: Gradient { //漸變屬性
            GradientStop{//從上到下顏色漸變,需要從做到右使用屬性rotation設置90即可
                position: 0.0; color: "red"
            }
            GradientStop{
                position: 1.0; color: "blue"
            }
        }
    }

    Label{
        id:label2;
        text:"value";
        anchors.top: message3.top
        x:570
    }
    //底部
    Rectangle{
        height: 40
        width: 550
        anchors.bottom: parent.bottom
        id:bottomrect
        Row{
            TextField{
                id:textfield
                placeholderText: "輸入內容"
                height:bottomrect.height
                width:window.width*0.7

            }
        }
        Button{
            id:button1
            text:"Send"
            x:560
            anchors.top: message3.bottom
            onClicked: {
                listmodel.append({"detail":textfield.text})
                client.obtain_message(textfield.text);
                //textfield.text=''
            }
        }
        Client
        {
            id:client
        }
        Button
        {
            id:button2
            text:"Connect"
            anchors.left: button1.right
            onClicked:
            {
                label2.text=client.mystring
                client.connect_server();
                //client.communication();
            }
            //連接信號 到qml
            Connections{
                target:client;
                onMystringChanged:label2.text = str;
                //這裏的value是signal信號函數裏面的參數
            }
        }
        Button
        {
            id:button3
            text:"Quit"
            anchors.left: button2.right
            onClicked:
            {
                window.close();
            }
        }

    }

    ListView{
        width:200
        height:550
        add: Transition {
            //設置增加Item時的動畫 from 100,100  to不設置 就是默認在ListView
            NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
        }
        id:listview2
        anchors.top: parent.top
        anchors.bottom: bottomrect.top
        anchors.left:parent.left
        anchors.right:parent.right
        //anchors的對象要麼是兄弟結點(提供id)
        //要麼就是子節點(parent)
        delegate:Component{ //這裏delegate:後面必須是Component
            Rectangle{
                width:200
                height:label3.height
                opacity: 0.8
                BorderImage{
                    //聊天氣泡
                    id:qipao
                    source:"pao.png"
                    width:label3.width+30
                    height:label3.height<=30?30:label3.height+5
                    //  width:20
                    border.left: 10
                    border.right: 10
                    border.top:10
                    border.bottom:10
                    x:parent.width-width
                    Text{
                        id:label3
                        /*************
                             此處爲可變大小的聊天氣泡的重點
                             根據獲取值的長度和每個字佔的像素
                             *************/
                        width:label3.text.length<=10?label3.text.length*12:120
                        font.pixelSize: 12
                        anchors.centerIn:parent
                        anchors.leftMargin:10
                        wrapMode: Text.Wrap //多行文本 超過width就自動換行
                        text:detail
                    }
                }
            }
        }
        model:ListModel{
            id:listmodel2
            ListElement{
                detail:""
            }
        }
    }
    Rectangle{
        anchors.top: parent.top
        id:bottomrect2
        Row{
            Text{
                id:textfield2
                height:bottomrect2.height
                width:window.width*0.7
                // anchors.top : ListView.top
            }
        }
    }
    Button
    {
        id:button4
        text:"recvmsg"
        x:720
        y:510
        anchors.left: button3.right
        onClicked:
        {
            listmodel2.append({"detail":textfield2.text})
            textfield2.text=client.message
        }
        Connections{
            target:client;
            onMessageChanged: textfield2.text = str;
        }
    }



}
/*
Window {
    width:200
    height: 100
    visible: true
    Button{
        id:btn1;
        height:20;
        width:60;
        text:"button";
        onClicked: {
            //qml操作c++
            //btn1.text=myobj.mystring;
            label1.text = myobj.mystring;
        }
    }
    Label{
        id:label1;
        text:"初始值";
        anchors.left:btn1.right;
    //創建對象        anchors.leftMargin: 12;
    }

    MyClassType
    {
         id:myobj;
    }
    //連接信號 到qml
    Connections{
        target:myobj;
        onMystringChanged:label1.text=value;
        //這裏的value是signal信號函數裏面的參數
    }

}*/

client.cpp

#include"client.h"
static SOCKET sclient;

client::client(QObject *parent)
    :QObject(parent)
{
    this->m_pstring = new QString;
    this->send_data = new QString;
    this->recv_data = new QString;
}

client::~client()
{
    delete this->m_pstring;
    delete this->send_data;
    delete this->recv_data;
}

QString client::get_send_data()
{
    return *recv_data;
}

QString client::getString()
{
    setString("connect succeed...");
    return *(this->m_pstring);
}
void client::setString(QString string)
{
    *(this->m_pstring)=string;
    emit mystringChanged(string);//發送信號
}


void client::setMessage(QString string)
{
    *recv_data=string;
}
void client::sendMessage(QString string)
{
    *send_data = string;
    qDebug()<<*send_data;
}


void client::obtain_message(QString string)
{
    *send_data = string;
    qDebug()<<*send_data;
}

void client::connect_server()
{
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA data;
    if (WSAStartup(sockVersion, &data) != 0)
    {
        exit(0);
    }
    sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sclient == INVALID_SOCKET)
    {
        printf("invalid socket!");
        exit(0);
    }
    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(8080);
    serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    if (::connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
    {
        printf("connect error !");
        closesocket(sclient);
        exit(0);
    }
    cout<<"connect succeed..."<<endl;

    start_thread1();
}


void client::communication()
{
    /*
    循環外先給recv創建單獨的線程
    循環發消息
    */
    start_thread2();
     char sendData[255];
    while(true)
    {
        //cout<<"sendmessage:";
       // cout<<"!!!!!!!!!!!!!!!!!!!!!!"<<endl;
        if( (*send_data).size() > 0)
        {
            QByteArray buffer =(*send_data).toUtf8();
            char *p =buffer.data();
            strcpy(sendData,p);
            sendData[strlen(sendData)]='\0';
            cout<<sendData<<endl;
            send(sclient, sendData, strlen(sendData), 0);
            *send_data = "\0";
            memset(sendData,0,strlen(sendData));
        }
    }

    closesocket(sclient);
    WSACleanup();
}

QString client::message()
{
    return *recv_data;
}
void client::recv_news()
{
    char recData[255];
    int ret = 0;
    int count = 0;
    while(true)
    {
        cout<<"~~~~~~~~~~~~~~~~~~~~~~~~"<<endl;
        ret = recv(sclient, recData, 255, 0);
        count++;
        if(count == 1)
        {
            cout<<"recv success!"<<endl;
        }
        if (ret>0)
        {
            recData[ret] = '\0';
            cout<<"recv a messgae:"<<recData<<endl;
            *recv_data = QString(QLatin1String(recData));
            emit messageChanged(*recv_data);
        }
        *recv_data="\0";
        memset(recData,0,255);
    }
}

void client::send_news()
{
    char sendData[255];
    //char sendData[]="This client ,hello server";
    //cout<<"!!!!!!!!!!!!!!!!!!!!!!"<<endl;
    if((*send_data).size() > 0)
    {
        QByteArray buffer =(*send_data).toUtf8();
        char *p =buffer.data();
        strcpy(sendData,p);
        sendData[strlen(sendData)]='\0';
        cout<<sendData<<endl;
        send(sclient, sendData, strlen(sendData), 0);
        //cout<<"Now,send the message to server."<<endl;
        *send_data = '\0';
        memset(sendData,0,strlen(sendData));
    }

}

void client::start_thread1()
{
    cout<<"start communicate."<<endl;
    std::thread t(&client::thread1,this);
    t.detach();
}

void* client::thread1(void* _this)
{
    client* p = (client*) _this;
    p->communication();
    return p;
}


void client::start_thread2()
{
    std::thread t(&client::thread2,this);
    t.detach();
}
void* client::thread2(void* _this)
{
    client*p = (client*) _this;
    p->recv_news();
    return p;
}


void client::start_thread3()
{
    std::thread t(&client::thread3,this);
    t.detach();
}
void* client::thread3(void* _this)
{
    client*p = (client*) _this;
    p->send_news();
    return p;
}

client.h

#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include<QString>
#include<Qtimer.h>
#include<thread>
#include<Windows.h>
#include<qdebug.h>
#pragma comment(lib,"ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<iostream>
using namespace std;
class client : public QObject
{
    Q_OBJECT
    //暴露給QML 屬性
    Q_PROPERTY(QString mystring READ getString WRITE setString NOTIFY mystringChanged)
    Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged)
public:
    explicit client(QObject *parent = 0);
    ~client();
    Q_INVOKABLE QString getString(); //Q_INVOCABLE暴露給 QML
    Q_INVOKABLE void setString(QString string); 
    Q_INVOKABLE QString message();


    Q_INVOKABLE void setMessage(QString string);
    Q_INVOKABLE void sendMessage(QString string);

    Q_INVOKABLE void obtain_message(QString str);
    Q_INVOKABLE QString get_send_data();
    void communication();
    void recv_news();
    void send_news();
signals:
    void  mystringChanged(QString value); //信號
    void  messageChanged(QString str);
public slots:    
    Q_INVOKABLE void connect_server();
    static void*thread1(void*);
    static void*thread2(void*);
    static void*thread3(void*);
    void start_thread1();
    void start_thread2();
    void start_thread3();
public:
    QString * m_pstring;
    QString *send_data;
    QString *recv_data;
};
#endif // MYCLASS_H

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include"client.h"
#include<QtQml>


int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    qmlRegisterType<client>("RegisterClient",1,0,"Client");
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

 

聊天小軟件使用方法:
1.運行Server與Client後,先啓動服務器點擊Connect,然後點擊客戶端Connect。
2.當右上方提示變爲waiting connect....與connect succeed後可以實現雙工發送與接收消息。


ps:左上角爲顯示的爲實時消息,點擊recvmsg按鈕可以把當前消息記錄並顯示消息在框中。

效果圖

注:聊天框,與圖標的素材可以任意選擇

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章