一、对象模型(对象树)
 
- 1、Qt引入对象树的概念,在一定程度上解决了内存问题;
- 2、当一个Q0bject对象在堆上创建的时候,Qt会同时为其创建一个对象树;
- 3、不过,对象树中对象的顺序是没有定义的;
- 4、这意味着,销毁这些对象的顺序也是未定义的;
在Qt中创建对象的时候会提供一个Parent对象指针,
下面来解释这个parent到底是干什么的。
------------------------------------------------
Q0bject是以对象树的形式组织起来的。
--------------------------------------------
当你创建一个Q0bject对象时,会看到Q0bject的构造函数接收一个
QObject指针作为参数,这个参数就是parent, 也就是父对象指针。
-------------------------------------------------------------------------------
----------------------------------------------------------------------
这相当于,在创建Q0bject对象时,可以提供一个其父对象,我们创建
的这个Q0bject对象会自动添加到其父对象的children()列表。
------------------------------------------------------------------------------
当父对象析构的时候,这个列表中的所有对象也会被析构。
(注意,这里的父对象并不是继承意义上的父类!)
---------------------------------------------------
这种机制在GUI程序设计中相当有用。
---------------------------------------------------------
例如,一个按钮有一个QShortcut (快捷键)对象作为其子对象。
当我们删除按钮的时候,这个快捷键理应被删除。
这是合理的。
--------------------------------------------------------------
QWidget 是能够在屏幕上显示的一切组件的父类。
----------------------------------------------------------------
QWidget继承自QObject,因此也继承了这种对象树关系。
一个孩子自动地成为父组件的一个子组件。
------------------------------------------------------------
因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。
例如,当用户关闭一个对话框的时候,应用程序将其删除,
那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。
事实就是如此,因为这些都是对话框的子组件。
--------------------------------------------------------------
当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。
---------------------------------------------------------------------------------
比如,当我们删除了一个工具栏时,
其所在的主窗口会自动将该工具栏从其子对象列表中删除,
并且自动调整屏幕显示。
任何对象树中的Q0bject 对象delete 的时候,
如果这个对象有parent,则自动将其从parent 的children()列表中删除;
如果有孩子,则自动delete每一个孩子。
Qt保证没有Q0bject会被delete 两次,这是由析构顺序决定的。
 
二、TCP服务器
 
server.pro
------------------
QT       += core gui network
----------------------------
widget.h
------------------
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_startBtn_clicked();
    void on_senderBtn_clicked();
private:
    Ui::Widget *ui;
    QTcpServer* server;
    QTcpSocket* socket;
};
#endif 
--------------------------------
widget.cpp
---------------------
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("服务器");
    
    this->server = new QTcpServer(this);
    this->socket = new QTcpSocket(this);
    
    connect(this->server,&QTcpServer::newConnection,[=](){
        
        this->socket = this->server->nextPendingConnection();
        ui->chatlogText->append("新的客户机连接了服务器");
        
        connect(this->socket,&QTcpSocket::readyRead,[=](){
            QString recvMsg = this->socket->readAll();
            ui->chatlogText->append("客户机发来的数据:" + recvMsg);
        });
        connect(this->socket,&QTcpSocket::disconnected,[=](){
            
            this->socket->deleteLater();
        });
    });
}
Widget::~Widget()
{
    delete ui;
}
void Widget::on_startBtn_clicked()
{
    quint16 port = ui->port_line->text().toUShort();
    this->server->listen(QHostAddress::Any,port);
    ui->startBtn->setEnabled(false);
}
void Widget::on_senderBtn_clicked()
{
    QString senderMsg = ui->senderText->toPlainText();
    this->socket->write(senderMsg.toUtf8());
    ui->senderText->clear();
}
 
三、TCP客户端
 
client.pro
--------------------
QT       += core gui network
------------------------------------
widget.h
----------------------
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_connectBtn_clicked();
    void on_disconnectBtn_clicked();
    void on_senderBtn_clicked();
private:
    Ui::Widget *ui;
    QTcpSocket* socket;
};
#endif 
------------------------
widget.cpp
---------------
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("客户端");
    this->socket = new QTcpSocket(this);
    
    connect(this->socket,&QTcpSocket::connected,[=](){
        ui->chatTextRoom->append("已经连接上服务器");
    });
    
    connect(this->socket,&QTcpSocket::readyRead,[=](){
        QString recvMsg = this->socket->readAll();
        ui->chatTextRoom->append(recvMsg);
    });
    
    connect(this->socket,&QTcpSocket::disconnected,[=](){
        this->socket->close();
    });
}
Widget::~Widget()
{
    delete ui;
}
void Widget::on_connectBtn_clicked()
{
    QString serverIP = ui->ip_line->text();
    quint16 serverPort = ui->port_line->text().toUShort();
    this->socket->connectToHost(serverIP,serverPort);
    ui->connectBtn->setEnabled(false);
}
void Widget::on_disconnectBtn_clicked()
{
    this->socket->close();
}
void Widget::on_senderBtn_clicked()
{
    QString senderMsg = ui->userName_line->text() + ": " + ui->senderMsgText->toPlainText();
    this->socket->write(senderMsg.toUtf8());
    ui->senderMsgText->clear();
}
 
四、TCP并发服务器
 
 
------------------------------------
mytcpserver.h:
----------------
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H
#include <QTcpServer>
#include <QTcpSocket>
class MyTcpServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit MyTcpServer(QObject *parent = nullptr);
    QList<QTcpSocket*> getSocketList();
protected:
    
    void incomingConnection(qintptr handle) override;
signals:
    void mytcpserver_signals(const QString& recvMsg);
private:
    QList<QTcpSocket*> socket_list;
};
#endif 
----------------------------
mytcpserver.cpp:
------------------------
#include "mytcpserver.h"
MyTcpServer::MyTcpServer(QObject *parent) : QTcpServer(parent)
{
}
QList<QTcpSocket *> MyTcpServer::getSocketList()
{
    return this->socket_list;
}
void MyTcpServer::incomingConnection(qintptr handle)
{
    
    QTcpSocket* socket = new QTcpSocket(this);
    
    socket->setSocketDescriptor(handle);
    
    this->socket_list.append(socket);
    
    connect(socket,&QTcpSocket::readyRead,[=](){
        QString recvMsg = socket->readAll();
        emit this->mytcpserver_signals(recvMsg);
        
        for(QTcpSocket* mysocket : this->socket_list)
        {
            mysocket->write(recvMsg.toUtf8());
        }
    });
    
    connect(socket,&QTcpSocket::disconnected,[=](){
        socket->close();
        this->socket_list.removeOne(socket);
    });
}
--------------------------------------------
widget.h:
--------------
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include "mytcpserver.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_startBtn_clicked();
    void on_senderBtn_clicked();
private:
    Ui::Widget *ui;
    MyTcpServer* server;
};
#endif 
--------------------------
widget.cpp:
-----------------
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("服务器");
    
    this->server = new MyTcpServer(this);
    
    connect(this->server,&MyTcpServer::mytcpserver_signals,[=](const QString& recvMsg){
        ui->chatlogText->append(recvMsg);
    });
}
Widget::~Widget()
{
    delete ui;
}
void Widget::on_startBtn_clicked()
{
    quint16 port = ui->port_line->text().toUShort();
    this->server->listen(QHostAddress::Any,port);
    ui->startBtn->setEnabled(false);
}
void Widget::on_senderBtn_clicked()
{
    QString senderMsg = ui->senderText->toPlainText();
    for(QTcpSocket* mysocket : this->server->getSocketList())
    {
        mysocket->write(senderMsg.toUtf8());
    }
    ui->senderText->clear();
}